/*
* 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 store.
*
*/


// INCLUDE FILES
#include "CPbk2CommandStore.h"

// Phonebook 2
#include <MPbk2Command.h>
#include <MPbk2MenuCommandObserver.h>

// --------------------------------------------------------------------------
// CPbk2CommandStore::CPbk2CommandStore
// --------------------------------------------------------------------------
//
inline CPbk2CommandStore::CPbk2CommandStore() :
iInputBlocker( NULL )
    {
    }

// --------------------------------------------------------------------------
// CPbk2CommandStore::~CPbk2CommandStore
// --------------------------------------------------------------------------
//
CPbk2CommandStore::~CPbk2CommandStore()
    {
    iIdleDestructableCommands.Reset();
    iIdleDestructableCommands.Close();
    iCommandObservers.Reset();
    iCommandObservers.Close();
    iCommandArray.ResetAndDestroy();
    iCommandArray.Close();
    delete iIdleDestroyer;
    delete iInputBlocker;
    }

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

// --------------------------------------------------------------------------
// CPbk2CommandStore::ConstructL
// --------------------------------------------------------------------------
//
inline void CPbk2CommandStore::ConstructL()
    {
    iIdleDestroyer = CIdle::NewL( CActive::EPriorityIdle );
    }

// --------------------------------------------------------------------------
// CPbk2CommandStore::AddMenuCommandObserver
// --------------------------------------------------------------------------
//
void CPbk2CommandStore::AddMenuCommandObserver
        ( MPbk2MenuCommandObserver& aObserver )
    {
    TRAP_IGNORE( iCommandObservers.AppendL( &aObserver ) );
    }


// --------------------------------------------------------------------------
// CPbk2CommandStore::RemoveMenuCommandObserver
// --------------------------------------------------------------------------
//
void CPbk2CommandStore::RemoveMenuCommandObserver
        ( MPbk2MenuCommandObserver& aObserver )
    {
    TInt index = iCommandObservers.Find( &aObserver );
    if ( index > KErrNotFound )
        {
        iCommandObservers.Remove( index );
        }
    }

// --------------------------------------------------------------------------
// CPbk2CommandStore::AddAndExecuteCommandL
// --------------------------------------------------------------------------
//
EXPORT_C void CPbk2CommandStore::AddAndExecuteCommandL
        ( MPbk2Command* aCommand )
    {
    const TInt KEmpty( 0 );
    if ( aCommand )
        {
        // If command array is empty, execute command.
        // Otherwise delete command to avoid overlapping commands.
        if ( iCommandArray.Count() == KEmpty )
            {
            // Avoid user input during command execution
            if( iInputBlocker )
                {
                iInputBlocker->Cancel();
                }
            iInputBlocker = CAknInputBlock::NewCancelHandlerLC( this );
            CleanupStack::Pop( iInputBlocker );   
            iInputBlocker->SetCancelDelete( iInputBlocker );
                        
            // notify all command observers
            for ( TInt i = 0; i < iCommandObservers.Count(); ++i )
                {
                iCommandObservers[i]->PreCommandExecutionL( *aCommand );
                }
            aCommand->AddObserver( *this );
                        
            // Some command observers needs always postcommand call,
            // if ExecuteLD leaves
            TRAPD( err, aCommand->ExecuteLD() );
            if ( err != KErrNone )
                {
                for (TInt i = 0; i < iCommandObservers.Count(); ++i)
                    {
                    // ignore leave, we are leaving anyway after this
                    TRAP_IGNORE
                        ( iCommandObservers[i]->PostCommandExecutionL( *aCommand ) );
                    }
                
                // stop user input blocker
                if( iInputBlocker )
                    {
                    iInputBlocker->Cancel();
                    }
                
                User::Leave( err );
                }
            User::LeaveIfError( iCommandArray.Append( aCommand ) );
            }
         else
            {
            delete aCommand;
            aCommand = NULL;
            }
        }
    }

// --------------------------------------------------------------------------
// CPbk2CommandStore::CommandFinished
// --------------------------------------------------------------------------
//
void CPbk2CommandStore::CommandFinished( const MPbk2Command& aCommand )
    {
    // notify all command observers
    for (TInt i = 0; i < iCommandObservers.Count(); ++i)
        {
        TRAP_IGNORE
            ( iCommandObservers[i]->PostCommandExecutionL( aCommand ) );
        }
    
    // stop user input blocker
    if( iInputBlocker )
        {
        iInputBlocker->Cancel();
        }

    // Add command to the list of idle destroyable objects
    iIdleDestructableCommands.Append( &aCommand );
    // Cancel any outstanding before starting new one.
    iIdleDestroyer->Cancel();
    // Request idle destruction. If the append above failed,
    // it doesn't matter. The command gets destructed then
    // at the Phonebook exit, when this objects destructor
    // deletes also commands in iCommandArray.
    iIdleDestroyer->Start( TCallBack(
        ( &CPbk2CommandStore::IdleDestructorCallback ),this ) );
    }

// --------------------------------------------------------------------------
// CPbk2CommandStore::AknInputBlockCancel
// --------------------------------------------------------------------------
//
void CPbk2CommandStore::AknInputBlockCancel()
	{
	iInputBlocker = NULL;
	}


// --------------------------------------------------------------------------
// CPbk2CommandStore::IdleDestructorCallback
// --------------------------------------------------------------------------
//
TInt CPbk2CommandStore::IdleDestructorCallback( TAny* aSelf )
    {
    CPbk2CommandStore* self = static_cast<CPbk2CommandStore*>( aSelf );
    self->IdleDestructor();
    return EFalse;
    }

// --------------------------------------------------------------------------
// CPbk2CommandStore::IdleDestructor
// --------------------------------------------------------------------------
//
void CPbk2CommandStore::IdleDestructor()
    {
    // Delete objects in idle destroyable array
    for (TInt i = 0; i < iIdleDestructableCommands.Count(); ++i)
        {
        MPbk2Command* idleDestCmd = iIdleDestructableCommands[i];
        for (TInt j = iCommandArray.Count()-1; j >= 0; --j)
            {
            MPbk2Command* arrayCmd = iCommandArray[j];
            if (idleDestCmd == arrayCmd)
                {
                // Remove from command array
                iCommandArray.Remove(j);
                iIdleDestructableCommands.Remove(i);
                delete idleDestCmd;
                idleDestCmd = NULL;
                }
            }
        }
    }


// --------------------------------------------------------------------------
// CPbk2CommandStore::DestroyAllCommands
// --------------------------------------------------------------------------
//
void CPbk2CommandStore::DestroyAllCommands()
    {
    // Delete objects in idle commands array using CommandFinished
    for (TInt i = 0; i < iCommandArray.Count(); ++i)
        {
        MPbk2Command* destCmd = iCommandArray[i];
        CommandFinished ( *destCmd );
        }
    }
// End of File
