/*
* 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 remove from group command.
*
*/


// INCLUDE FILES
#include "CPguRemoveFromGroupCmd.h"

// Phonebook2
#include <Pbk2GroupUIRes.rsg>
#include <MPbk2CommandObserver.h>
#include <MPbk2ContactUiControl.h>
#include <CPbk2GeneralConfirmationQuery.h>
#include <MPbk2ApplicationServices.h>
#include <MPbk2AppUi.h>

// Virtual Phonebook
#include <CVPbkContactManager.h>
#include <MVPbkContactLink.h>
#include <MVPbkContactGroup.h>
#include <MVPbkContactOperationBase.h>

// System includes
#include <coemain.h>
#include <eikprogi.h> // CEikProgessInfo
#include <akninputblock.h>

// Debugging headers
#include <Pbk2Debug.h>

/// Unnamed namespace for local definitions
namespace {

const TInt KOne( 1 );
const TInt KFirstContact( 0 );

#ifdef _DEBUG

enum TPanicCode
    {
    EPanicPreCond_ExecuteLD = 1,
    EPanicContactNotGroup, 
    EInvalidState,
    EPanicNullPointer
    };

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

#endif // _DEBUG

} /// namespace

// --------------------------------------------------------------------------
// CPbk2AknProgressDialog::CPbk2AknProgressDialog
// --------------------------------------------------------------------------
// 
CPbk2AknProgressDialog::CPbk2AknProgressDialog(
		CEikDialog** aSelfPtr,
		TBool aVisibilityDelayOff ):
	CAknProgressDialog( aSelfPtr, aVisibilityDelayOff ),
	iEndCallKeyPressed( EFalse )
	{
	
	}
		
// --------------------------------------------------------------------------
// CPbk2AknProgressDialog::~CPbk2AknProgressDialog
// --------------------------------------------------------------------------
//
CPbk2AknProgressDialog::~CPbk2AknProgressDialog()
    {

    }

// --------------------------------------------------------------------------
// CPbk2AknProgressDialog::OfferKeyEventL
// --------------------------------------------------------------------------
//
TKeyResponse CPbk2AknProgressDialog::OfferKeyEventL
        ( const TKeyEvent& aKeyEvent, TEventCode aType )
	{	
	if( aType == EEventKey  && aKeyEvent.iCode == EKeyEscape )
		{
		if( !iEndCallKeyPressed )
		    {
		    iEndCallKeyPressed = ETrue;
		    }
		}
	return CAknProgressDialog::OfferKeyEventL( aKeyEvent, aType );
	}

// --------------------------------------------------------------------------
// CPbk2AknProgressDialog::OkToExitL
// --------------------------------------------------------------------------
//
TBool CPbk2AknProgressDialog::OkToExitL(TInt aButtonId)
	{
	if( iEndCallKeyPressed )
		{
		iEndCallKeyPressed = EFalse;
	    if ( iCallback )
            {
            iCallback->DialogDismissedL(aButtonId);
            }
        return ETrue;
		}	
	return CAknProgressDialog::OkToExitL( aButtonId );
	}

// --------------------------------------------------------------------------
// CPguRemoveFromGroupCmd::CPguRemoveFromGroupCmd
// --------------------------------------------------------------------------
//    
CPguRemoveFromGroupCmd::CPguRemoveFromGroupCmd(
	    MVPbkContactLink& aContactGroup, 
	    MPbk2ContactUiControl& aUiControl ) :
	CActive( EPriorityIdle ),
    iUiControl( &aUiControl ),
    iGroupLink( aContactGroup )
    {
    PBK2_DEBUG_PRINT(PBK2_DEBUG_STRING
        ("CPguRemoveFromGroupCmd::CPguRemoveFromGroupCmd(0x%x)"),this);
    CActiveScheduler::Add( this );
    }

// --------------------------------------------------------------------------
// CPguRemoveFromGroupCmd::~CPguRemoveFromGroupCmd
// --------------------------------------------------------------------------
//
CPguRemoveFromGroupCmd::~CPguRemoveFromGroupCmd()
    {
    PBK2_DEBUG_PRINT(PBK2_DEBUG_STRING
        ("CPguRemoveFromGroupCmd::~CPguRemoveFromGroupCmd(0x%x)"),
        this);
	Cancel();
    if( iUiControl )
        {
        iUiControl->RegisterCommand( NULL );
        }
	
	delete iSelectedContacts;
	delete iProgressDialog;
	delete iStoreContact;
    delete iRetrieveOperation;
    delete iContactGroup;
    delete iInputBlock;
    }

// --------------------------------------------------------------------------
// CPguRemoveFromGroupCmd::NewLC
// --------------------------------------------------------------------------
//
CPguRemoveFromGroupCmd* CPguRemoveFromGroupCmd::NewLC(
        MVPbkContactLink& aContactGroup, 
        MPbk2ContactUiControl& aUiControl )
    {
    CPguRemoveFromGroupCmd* self = new(ELeave) CPguRemoveFromGroupCmd(
                                        aContactGroup, aUiControl );
    CleanupStack::PushL( self );
    self->ConstructL();
    return self;
    }

// --------------------------------------------------------------------------
// CPguRemoveFromGroupCmd::ConstructL
// --------------------------------------------------------------------------
//
inline void CPguRemoveFromGroupCmd::ConstructL()
    {
    // UI input not allowed during async. operation
    ReactivateUIBlockL();   
    
    // Save focus 
    iFocusedContactIndex = iUiControl->FocusedContactIndex();

	iSelectedContacts = iUiControl->SelectedContactsOrFocusedContactL();
	__ASSERT_DEBUG(iSelectedContacts, Panic(EPanicNullPointer));
	iTotalContactsToRemove = iSelectedContacts->Count();    
    iUiControl->RegisterCommand( this );
    }

// --------------------------------------------------------------------------
// CPguRemoveFromGroupCmd::ExecuteLD
// --------------------------------------------------------------------------
//
void CPguRemoveFromGroupCmd::ExecuteLD()
    {
    __ASSERT_DEBUG(iCommandObserver, Panic(EPanicPreCond_ExecuteLD));
    
    PBK2_DEBUG_PRINT(PBK2_DEBUG_STRING
        ("CPguRemoveFromGroupCmd::ExecuteLD(0x%x)"), this);

    CleanupStack::PushL( this );
	 
    if ( iSelectedContacts )
        {
        if ( iSelectedContacts->Count() > KOne )
            {
            // Move straight to confirm phase
            iState = EConfirming;
            IssueRequest();
            }
        else if ( iSelectedContacts->Count() == KOne )
            {
            // If the array contains only one contact, we have to retrieve it
            // to get its name for the confirmation query
            iState = ERetrieving;
            IssueRequest();
            }
        }
        
    CleanupStack::Pop( this );
    }  

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

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

// --------------------------------------------------------------------------
// CPguRemoveFromGroupCmd::DoCancel
// --------------------------------------------------------------------------
//
void CPguRemoveFromGroupCmd::DoCancel()
    {
    delete iRetrieveOperation;
    iRetrieveOperation = NULL;
    if (iUiControl)
        {
        iUiControl->SetBlank( EFalse );
        }    
    TRAP_IGNORE( DeleteProgressNoteL() );
    }

// --------------------------------------------------------------------------
// CPguRemoveFromGroupCmd::RunL
// --------------------------------------------------------------------------
//    
void CPguRemoveFromGroupCmd::RunL()
    {
    PBK2_DEBUG_PRINT
        (PBK2_DEBUG_STRING("CPguRemoveFromGroupCmd::RunL()"), this);

	switch ( iState )
		{
		case ERetrieving:
			{
			// UI input not allowed during async. operation
			ReactivateUIBlockL();	
			
            const MVPbkContactLink& link =
                iSelectedContacts->At( KFirstContact );
            RetrieveContactL( link );
			break; 
			}
		case EConfirming:
			{
			ConfirmRemovingL();
			break;
			}
		case ERetrievingGroupContact:
			{
	         // UI input not allowed during async. operation
	        ReactivateUIBlockL();
	        
			InitProgressDlgL();
			RetrieveContactL( iGroupLink );
			break;
			}
		case ERemoving:
			{
			HandleRemovingL();
			break;
			}
		case ECompleting:
	        {
	        CompleteL();
            DeleteProgressNoteL();
            break;	        
	        }
        case ECompletingWithError:
            {
            CompleteWithError();
            DeleteProgressNoteL();
            break;
            }
		default:
		    {
            __ASSERT_DEBUG( EFalse, Panic( EInvalidState ) );
		    break;
		    }
		}		

    PBK2_DEBUG_PRINT
        (PBK2_DEBUG_STRING("CPguRemoveFromGroupCmd::RunL end")); 
    }

// --------------------------------------------------------------------------
// CPguRemoveFromGroupCmd::RunError
// --------------------------------------------------------------------------
//
TInt CPguRemoveFromGroupCmd::RunError( TInt aError )
    {
    iCommandObserver->CommandFinished( *this );
    return aError;
    }    

// --------------------------------------------------------------------------
// CPguRemoveFromGroupCmd::VPbkSingleContactOperationComplete
// --------------------------------------------------------------------------
//    
void CPguRemoveFromGroupCmd::VPbkSingleContactOperationComplete
        ( MVPbkContactOperationBase& /*aOperation*/,
          MVPbkStoreContact* aContact )
    {
    delete iRetrieveOperation;
    iRetrieveOperation = NULL;
    
    if ( iState == ERetrievingGroupContact )
    	{
	    iContactGroup = aContact->Group();    	

	    __ASSERT_DEBUG(iContactGroup, Panic(EPanicContactNotGroup));
	        
	    TRAPD( error, iContactGroup->LockL( *this ) );
        
        if ( error != KErrNone )
            {            
            CCoeEnv::Static()->HandleError( error );
            
            iState = ECompletingWithError;
            IssueRequest();
            }
	    }
	else
		{
		// We now have a store contact and we can issue a confirmation
        iStoreContact = aContact;
        iState = EConfirming;
        IssueRequest();
		}
    }

// --------------------------------------------------------------------------
// CPguRemoveFromGroupCmd::VPbkSingleContactOperationFailed
// --------------------------------------------------------------------------
//    
void CPguRemoveFromGroupCmd::VPbkSingleContactOperationFailed
        ( MVPbkContactOperationBase& /*aOperation*/,  TInt aError )
    {
    delete iRetrieveOperation;
    iRetrieveOperation = NULL;
    
    iState = ECompletingWithError;
    IssueRequest();

    CCoeEnv::Static()->HandleError( aError );
    }

// --------------------------------------------------------------------------
// CPguRemoveFromGroupCmd::ContactOperationCompleted
// --------------------------------------------------------------------------
//
void CPguRemoveFromGroupCmd::ContactOperationCompleted
        ( TContactOpResult aResult )
    {
    if ( aResult.iOpCode == MVPbkContactObserver::EContactLock )
        {        		
        iState = ERemoving;
        IssueRequest();
        }
	else if ( aResult.iOpCode == MVPbkContactObserver::EContactCommit )
        {
        if ( iCommandObserver )
            {
            iCommandObserver->CommandFinished( *this );
            }
        }	
    }

// --------------------------------------------------------------------------
// CPguRemoveFromGroupCmd::ContactOperationFailed
// --------------------------------------------------------------------------
//    
void CPguRemoveFromGroupCmd::ContactOperationFailed
        ( TContactOp /*aOpCode*/, TInt aErrorCode, TBool aErrorNotified )
    {
    iState = ECompletingWithError;
    IssueRequest();

    if ( !aErrorNotified )
        {
        CCoeEnv::Static()->HandleError( aErrorCode );
        }
    }

// --------------------------------------------------------------------------
// CPguRemoveFromGroupCmd::ContactViewReady
// --------------------------------------------------------------------------
//	
void CPguRemoveFromGroupCmd::ContactViewReady
        ( MVPbkContactViewBase& /*aView*/ )
	{
	// Do nothing
	}

// --------------------------------------------------------------------------
// CPguRemoveFromGroupCmd::ContactViewUnavailable
// --------------------------------------------------------------------------
//	
void CPguRemoveFromGroupCmd::ContactViewUnavailable
        ( MVPbkContactViewBase& /*aView*/ )
	{
	// Do nothing
	}

// --------------------------------------------------------------------------
// CPguRemoveFromGroupCmd::ContactAddedToView
// --------------------------------------------------------------------------
//	
void CPguRemoveFromGroupCmd::ContactAddedToView
        ( MVPbkContactViewBase& /*aView*/, TInt /*aIndex*/,
          const MVPbkContactLink& /*aContactLink*/ )
	{
	// Do nothing
	}

// --------------------------------------------------------------------------
// CPguRemoveFromGroupCmd::ContactRemovedFromView
// --------------------------------------------------------------------------
//	
void CPguRemoveFromGroupCmd::ContactRemovedFromView
        ( MVPbkContactViewBase& /*aView*/, TInt /*aIndex*/,
          const MVPbkContactLink& /*aContactLink*/ )
	{
	// Do nothing
	}

// --------------------------------------------------------------------------
// CPguRemoveFromGroupCmd::ContactViewError
// --------------------------------------------------------------------------
//	
void CPguRemoveFromGroupCmd::ContactViewError
        ( MVPbkContactViewBase& /*aView*/, TInt aError,
          TBool /*aErrorNotified*/ )
	{
    iState = ECompletingWithError;
    IssueRequest();

    CCoeEnv::Static()->HandleError( aError );
	}

// --------------------------------------------------------------------------
// CPguRemoveFromGroupCmd::DialogDismissedL
// --------------------------------------------------------------------------
//
void CPguRemoveFromGroupCmd::DialogDismissedL( TInt /*aButtonId*/ )
    {
    PBK2_DEBUG_PRINT(PBK2_DEBUG_STRING(
        "CPbkRemoveFromGroupCmd::DialogDismissedL"));
        
    iProgressDialog = NULL;        
    iDialogDismissed = ETrue;    
    // Notify command owner that the command has finished
    if ( iCommandObserver )
        {
        iCommandObserver->CommandFinished( *this );
        }
    }

// --------------------------------------------------------------------------
// CPguRemoveFromGroupCmd::MoreContactsToRemove
// --------------------------------------------------------------------------
//
inline TBool CPguRemoveFromGroupCmd::MoreContactsToRemove() const
    {
    return ( iSelectedContacts && 
        ( iTotalContactsToRemove > iRemovedCount ) );
    }

// --------------------------------------------------------------------------
// CPguRemoveFromGroupCmd::IsProcessDone
// --------------------------------------------------------------------------
//	
TBool CPguRemoveFromGroupCmd::IsProcessDone() const
    {
    return !MoreContactsToRemove();
    }

// --------------------------------------------------------------------------
// CPguRemoveFromGroupCmd::StepL
// --------------------------------------------------------------------------
//
void CPguRemoveFromGroupCmd::StepL()
    {
    PBK2_DEBUG_PRINT
        (PBK2_DEBUG_STRING("CPbkRemoveFromGroup::StepL()"), this);

    if ( MoreContactsToRemove() && 
         iSelectedContacts->Count() > iRemovedCount )
        {
        const MVPbkContactLink& contactLink = 
        	iSelectedContacts->At( iRemovedCount );
        TRAPD( err, iContactGroup->RemoveContactL( contactLink ) );
        if ( err == KErrInUse )
            {
            // If there is only one contact that failed, 
            // system error info note is shown and the process is terminated.
            if ( iSelectedContacts->Count() == KOne )
                {
                CCoeEnv::Static()->HandleError( err ); 
                iState = ECompletingWithError;
                }
            }
        else
            {
            User::LeaveIfError( err ); 
            }
        ++iRemovedCount;
        }
    }

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

// --------------------------------------------------------------------------
// CPguRemoveFromGroupCmd::CompleteL
// --------------------------------------------------------------------------
//
void CPguRemoveFromGroupCmd::CompleteL()
    {
    PBK2_DEBUG_PRINT(PBK2_DEBUG_STRING(
        "CPguRemoveFromGroupCmd::ProcessFinished(0x%x)"), this);

    if ( iUiControl )
        {
        iUiControl->SetBlank( EFalse );
        // Try to set focused contact
        iUiControl->SetFocusedContactIndexL( iFocusedContactIndex );
        // Clear listbox selections
        iUiControl->UpdateAfterCommandExecution();
        }
    }

// --------------------------------------------------------------------------
// CPguRemoveFromGroupCmd::CompleteWithError
// --------------------------------------------------------------------------
//   
void CPguRemoveFromGroupCmd::CompleteWithError()
    {
    if ( iUiControl )
        {
        iUiControl->SetBlank( EFalse );
        }
    }

// --------------------------------------------------------------------------
// CPguRemoveFromGroupCmd::DeleteProgressNoteL
// --------------------------------------------------------------------------
//    	
void CPguRemoveFromGroupCmd::DeleteProgressNoteL()
    {
    PBK2_DEBUG_PRINT(PBK2_DEBUG_STRING(
        "CPguRemoveFromGroupCmd::DeleteProgressNote start"));
        
    if ( iProgressDialog && !iDialogDismissed )
        {
        // Delete the dialog
        iProgressDialog->ProcessFinishedL();
        iProgressDialog = NULL;
        }
    else if ( iCommandObserver )
        {        
        iCommandObserver->CommandFinished( *this );
        }

    PBK2_DEBUG_PRINT(PBK2_DEBUG_STRING(
        "CPguRemoveFromGroupCmd::DeleteProgressNote end"));
    }

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

// --------------------------------------------------------------------------
// CPguRemoveFromGroupCmd::ConfirmRemovingL
// --------------------------------------------------------------------------
//	
void CPguRemoveFromGroupCmd::ConfirmRemovingL()
	{
	// When popping up the query, the input block will lose its focus, and it can't 
    // block the event. So delete the input block before the query pops up.
    if (iInputBlock)
        {
        delete iInputBlock;
        iInputBlock = NULL;
        }
    
    //original we will ask user if they really want to remove contacts from group,
    //but currently we decide that we will just do it without asking user
    TInt count = iSelectedContacts->Count();
    if (count >= 1)
        {
        // If the query result is confirm, restart the input block again to
        // keep blocking other event during the command execution.
        if (!iInputBlock)
            {
            iInputBlock = CAknInputBlock::NewLC();
            CleanupStack::Pop(iInputBlock);
            }

        // Retrieve the group contact
        iState = ERetrievingGroupContact;
        IssueRequest();
        }
    else
        {
        // Complete command, leave UI control as it was
        iState = ECompletingWithError;
        IssueRequest();
        }
	
	

	}

// --------------------------------------------------------------------------
// CPguRemoveFromGroupCmd::InitProgressDlgL
// --------------------------------------------------------------------------
//    
void CPguRemoveFromGroupCmd::InitProgressDlgL()
	{
    PBK2_DEBUG_PRINT(PBK2_DEBUG_STRING(
        "CPguRemoveFromGroupCmd::InitProgressDlgL"));
    
    if ( iUiControl )
        {
        iUiControl->SetBlank( ETrue );
        }
    
    CAknProgressDialog* progressDialog = new(ELeave) CPbk2AknProgressDialog(
            reinterpret_cast<CEikDialog**>(NULL), EFalse );
    progressDialog->PrepareLC( R_QTN_PHOB2_WNOTE_REM_FROM_GROUP );
    iProgressDlgInfo = progressDialog->GetProgressInfoL();
    iProgressDlgInfo->SetFinalValue( iTotalContactsToRemove );
    progressDialog->SetCallback( this );
    iDialogDismissed = EFalse;
    progressDialog->RunLD();
    iProgressDialog = progressDialog;	
    
    PBK2_DEBUG_PRINT(PBK2_DEBUG_STRING(
        "CPguRemoveFromGroupCmd::InitProgressDlgL end"));
	}

// --------------------------------------------------------------------------
// CPguRemoveFromGroupCmd::HandleRemovingL
// --------------------------------------------------------------------------
//
void CPguRemoveFromGroupCmd::HandleRemovingL()
	{
    if ( !IsProcessDone() )
        {
        // Process one step
        StepL();
        
        // Incrementing progress of the process
        iProgressDlgInfo->SetAndDraw( iRemovedCount );

        // Issue request to remove next item
        IssueRequest();
        }
    else
        {
        // Process is completed, all entries have been removed
        iState = ECompleting;
        IssueRequest();
        }	
	}

// --------------------------------------------------------------------------
// CPguRemoveFromGroupCmd::ReactivateUIBlockL
// --------------------------------------------------------------------------
//
void CPguRemoveFromGroupCmd::ReactivateUIBlockL()
    {
    // Use CAknInputBlock to block user input
    
    if( iInputBlock )
        {
        delete iInputBlock;
        iInputBlock = NULL;
        }
    
    iInputBlock = CAknInputBlock::NewLC();
    CleanupStack::Pop( iInputBlock );   
    }

//  End of File  
