/*
* Copyright (c) 2002-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:  The remote sim view implementation
*  Version     : %version: he1s60#21.1.3 %
*
*/



// INCLUDE FILES
#include "CRemoteView.h"

// From Virtual Phonebook
#include "CRemoteStore.h"
#include "VPbkSimStoreError.h"
#include <MVPbkSimViewObserver.h>
#include <VPbkSimServerOpCodes.h>
#include <CVPbkSimContactBuf.h>
#include <CVPbkAsyncOperation.h>
#include <CVPbkAsyncCallback.h>
#include <CVPbkSimFieldTypeFilter.h>
#include <MVPbkSimViewFindObserver.h>
#include <VPbkSimStoreTemplateFunctions.h>

#include <s32mem.h>

namespace VPbkSimStore {

inline void SendEvent(
    RPointerArray<MVPbkSimViewObserver>& aObservers,
    void ( MVPbkSimViewObserver::*aEvent )( MVPbkSimCntView& ),
    CRemoteView& aThis )
    {
    for ( TInt i = aObservers.Count() - 1; i >= 0; --i )
        {
        ( aObservers[i]->*aEvent )( aThis );
        }    
    }
    
inline void SendEvent(
    RPointerArray<MVPbkSimViewObserver>& aObservers,
    void ( MVPbkSimViewObserver::*aEvent )( MVPbkSimCntView&, TInt ),
    CRemoteView& aThis,
    TInt aParam )
    {
    for ( TInt i = aObservers.Count() - 1; i >= 0; --i )
        {
        ( aObservers[i]->*aEvent )( aThis, aParam );
        }    
    }
    
inline void SendEvent(
    RPointerArray<MVPbkSimViewObserver>& aObservers,
    void ( MVPbkSimViewObserver::*aEvent )
        ( MVPbkSimViewObserver::TEvent, TInt, TInt ),
    MVPbkSimViewObserver::TEvent aEventType,
    TInt aParam1,
    TInt aParam2 )
    {
    for ( TInt i = aObservers.Count() - 1; i >= 0; --i )
        {
        ( aObservers[i]->*aEvent )( aEventType, aParam1, aParam2 );
        }    
    }


// ============================ MEMBER FUNCTIONS ============================
// --------------------------------------------------------------------------
// CRemoteView::CViewFindOperation::CViewFindOperation
// C++ default constructor can NOT contain any code, that
// might leave.
// --------------------------------------------------------------------------
//
CRemoteView::CViewFindOperation::CViewFindOperation( 
	    const MDesCArray& aFindStrings,             
        MVPbkSimViewFindObserver& aObserver,
        RVPbkSimCntView& aSimCntViewSession,
        MVPbkSimCntView& aSimCntView ):
    CActive( EPriorityStandard ),
    iFindStrings( aFindStrings ),
    iObserver( aObserver ),
    iSimCntViewSession( aSimCntViewSession ),
    iSimCntView(aSimCntView),
    iSimMatchResultBufPtr( NULL, 0 )
    {
    }

// --------------------------------------------------------------------------
// CRemoteView::CViewFindOperation::ConstructL
// Symbian 2nd phase constructor can leave.
// --------------------------------------------------------------------------
//
void CRemoteView::CViewFindOperation::ConstructL()
    {
    CActiveScheduler::Add( this );           
    }

// --------------------------------------------------------------------------
// CRemoteView::CViewFindOperation::NewL
// Two-phased constructor.
// --------------------------------------------------------------------------
//
CRemoteView::CViewFindOperation* CRemoteView::CViewFindOperation::NewL( 
        const MDesCArray& aFindStrings, 
        MVPbkSimViewFindObserver& aObserver,
        RVPbkSimCntView& aSimCntViewSession,
        MVPbkSimCntView& aSimCntView )
    {
    CViewFindOperation* self = 
        new( ELeave ) CViewFindOperation( aFindStrings, aObserver, 
                                          aSimCntViewSession, aSimCntView );
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );
    return self;
    }

// Destructor
CRemoteView::CViewFindOperation::~CViewFindOperation()
    {
    Cancel();    
    delete iSimMatchResultBuf;
    }

// --------------------------------------------------------------------------
// CRemoteView::CViewFindOperation::ActivateL
// --------------------------------------------------------------------------
//
void CRemoteView::CViewFindOperation::ActivateL()
    {
    SetActive();
    iSimCntViewSession.ContactMatchingPrefixL( iFindStrings, 
                                               iResultBufferSize, 
                                               iStatus );    
    }

// --------------------------------------------------------------------------
// CRemoteView::CViewFindOperation::RunL
// --------------------------------------------------------------------------
//
void CRemoteView::CViewFindOperation::RunL()
    {
    RVPbkStreamedIntArray matchedIndexes;
    CleanupClosePushL( matchedIndexes );

    TInt result = iStatus.Int();
    switch ( result )
        {
        case KErrNone:
            {    
            //Delete old buffer        
            if ( iSimMatchResultBuf )
                {
                delete iSimMatchResultBuf;
                iSimMatchResultBuf = NULL;
                }
            
            //Create buffer
            iSimMatchResultBuf = HBufC8::NewL( iResultBufferSize );
            iSimMatchResultBufPtr.Set( iSimMatchResultBuf->Des() );                
              
            //Get contact matching results
            iSimCntViewSession.ContactMatchingResultL( iSimMatchResultBufPtr );
                            
            //Unpack results
            RDesReadStream stream( iSimMatchResultBufPtr );
            CleanupClosePushL( stream );
            matchedIndexes.InternalizeL( stream );
            CleanupStack::PopAndDestroy(); // stream
                        
            iObserver.ViewFindCompleted( iSimCntView, matchedIndexes );            
            break;
            }            
        default:
            {
            iObserver.ViewFindError( iSimCntView, result );
            break;
            }
        }
    CleanupStack::PopAndDestroy(); // matchedIndexes
    }
  
// --------------------------------------------------------------------------
// CRemoteView::CViewFindOperation::DoCancel
// --------------------------------------------------------------------------
//
void CRemoteView::CViewFindOperation::DoCancel()
    {
    iSimCntViewSession.CancelAsyncRequest( EVPbkSimSrvContactMatchingPrefix );
    }

// --------------------------------------------------------------------------
// CRemoteView::CViewFindOperation::RunError
// --------------------------------------------------------------------------
//
TInt CRemoteView::CViewFindOperation::RunError( TInt aError )
    {
    iObserver.ViewFindError( iSimCntView, aError );
    return KErrNone;
    }    

// --------------------------------------------------------------------------
// CRemoteView::CRemoteView
// C++ default constructor can NOT contain any code, that
// might leave.
// --------------------------------------------------------------------------
//
CRemoteView::CRemoteView( CRemoteStore& aStore,
        TVPbkSimViewConstructionPolicy aConstructionPolicy,
        CVPbkSimFieldTypeFilter* aFilter ) :
            CActive( EPriorityStandard ),
            iStore( aStore ),
            iConstructionPolicy( aConstructionPolicy ),
            iFilter( aFilter )
    {
    }

// --------------------------------------------------------------------------
// CRemoteView::~CRemoteView
// Destructor
// --------------------------------------------------------------------------
// 
CRemoteView::~CRemoteView()
    {
    delete iObserverOp;
    iObservers.Reset();
    iSortOrder.Close();
    iStore.RemoveObserver( *this );
    Cancel();
    delete iCurrentContact;
    iSimView.Close();
    delete iViewName;
    delete iFilter;
    }

// --------------------------------------------------------------------------
// CRemoteView::NewLC
// Two-phased constructor.
// --------------------------------------------------------------------------
//
CRemoteView* CRemoteView::NewL( CRemoteStore& aStore,
        const RVPbkSimFieldTypeArray& aSortOrder, 
        TVPbkSimViewConstructionPolicy aConstructionPolicy,
        const TDesC& aViewName,
        CVPbkSimFieldTypeFilter* aFilter )
    {
    CRemoteView* self = 
        new( ELeave ) CRemoteView( aStore, aConstructionPolicy, aFilter );
    CleanupStack::PushL( self );
    self->ConstructL( aSortOrder, aViewName );
    CleanupStack::Pop( self );
    return self;
    }

// --------------------------------------------------------------------------
// CRemoteView::ConstructL
// Symbian 2nd phase constructor can leave.
// --------------------------------------------------------------------------
//
void CRemoteView::ConstructL( const RVPbkSimFieldTypeArray& aSortOrder,
    const TDesC& aViewName )
    {
    CActiveScheduler::Add( this );
    SetSortOrderL( aSortOrder );
    iViewName = aViewName.AllocL();
    iCurrentContact = CVPbkSimContactBuf::NewL( iStore );
    iStore.AddObserverL( *this );
    iObserverOp = CVPbkAsyncObjectOperation<MVPbkSimViewObserver>::NewL();
    }


// --------------------------------------------------------------------------
// CRemoteView::RunL
// --------------------------------------------------------------------------
//
void CRemoteView::RunL()
    {
    if ( iStatus == KErrNone )
        {
        switch ( iEventData.iEvent )
            {   
            case EVPbkSimViewOpen:
                {
                SendEvent(iObservers, &MVPbkSimViewObserver::ViewReady, *this);
                break;
                }
            case EVPbkSimViewNotAvailable:
                {
                SendEvent(iObservers, &MVPbkSimViewObserver::ViewNotAvailable, *this);
                break;
                }
            case EVPbkSimContactAdded:
                {
                SendEvent(iObservers, &MVPbkSimViewObserver::ViewContactEvent, 
                          MVPbkSimViewObserver::EContactAdded, 
                          iEventData.iData, iEventData.iOpData );
                break;
                }
            case EVPbkSimContactDeleted:
                {
                SendEvent(iObservers, &MVPbkSimViewObserver::ViewContactEvent, 
                          MVPbkSimViewObserver::EContactDeleted, 
                          iEventData.iData, iEventData.iOpData );
                break;
                }
            case EVPbkSimViewError:
                {
                SendEvent(iObservers, &MVPbkSimViewObserver::ViewError, 
                          *this, iEventData.iOpData );
                break;
                }
            case EVPbkSimUnknown: // FALLTHROUGH
            default:
                {
                __ASSERT_DEBUG( EFalse, VPbkSimStore::Panic( 
                    VPbkSimStore::EUnknownViewEventFromServer ) );
                SendEvent(iObservers, &MVPbkSimViewObserver::ViewError, 
                          *this, KErrUnknown );
                break;
                }
            }
        }
    else
        {
        SendEvent(iObservers, &MVPbkSimViewObserver::ViewError, 
                  *this, iStatus.Int() );
        }

    ActivateViewNotification();
    }

// --------------------------------------------------------------------------
// CRemoteView::DoCancel
// --------------------------------------------------------------------------
//
void CRemoteView::DoCancel()
    {
    iSimView.CancelAsyncRequest( EVPbkSimSrvViewEventNotification );
    }

// --------------------------------------------------------------------------
// CRemoteView::Name
// --------------------------------------------------------------------------
//
const TDesC& CRemoteView::Name() const
    {
    return *iViewName;
    }
    
// --------------------------------------------------------------------------
// CRemoteView::ParentStore
// --------------------------------------------------------------------------
//
MVPbkSimCntStore& CRemoteView::ParentStore() const
    {
    return iStore;
    }

// --------------------------------------------------------------------------
// CRemoteView::OpenL
// --------------------------------------------------------------------------
//
void CRemoteView::OpenL( MVPbkSimViewObserver& aObserver )
    {
    TInt index = iObservers.Find(&aObserver);
    __ASSERT_DEBUG( index == KErrNotFound, 
        Panic( ERemoteViewObserverAlreadySet ) );
    iObservers.AppendL(&aObserver);
    
    // Open view subsession only if the store has been opened
    // This is actually called only from CContactView::ConstructL so
    // it's called only once -> not need to make else-clause for async
    if ( iStore.IsOpen() && !iSimView.SubSessionHandle())
        {
        iSimView.OpenL( iStore.StoreSession(), iSortOrder, iConstructionPolicy, 
            *iViewName, iFilter );
        ActivateViewNotification();
        }
    else
        {
        // Complete with "View unavailable" event
        CVPbkAsyncObjectCallback<MVPbkSimViewObserver>* callback =
            VPbkEngUtils::CreateAsyncObjectCallbackLC(
                *this, 
                &CRemoteView::DoViewUnavailableL,
                &CRemoteView::DoViewUnavailableError,
                aObserver );
        
        iObserverOp->CallbackL( callback );
        CleanupStack::Pop( callback ); // openCallback
        }
    }

// --------------------------------------------------------------------------
// CRemoteView::Close
// --------------------------------------------------------------------------
//
void CRemoteView::Close( MVPbkSimViewObserver& aObserver )
    {
    // Cancel the possible call back
    iObserverOp->CancelCallback( &aObserver );
    
    // Remove from the observer list
    TInt index = iObservers.Find(&aObserver);
    if (index != KErrNotFound)
        {
        iObservers.Remove(index);
        }
    
    // If it was the last user then close the connection to the server.
    if (iObservers.Count() == 0)
        {
        Cancel();
        iSimView.Close();
        }
    }
        
// --------------------------------------------------------------------------
// CRemoteView::CountL
// --------------------------------------------------------------------------
// 
TInt CRemoteView::CountL() const
    {
    return iSimView.CountL();
    }

// --------------------------------------------------------------------------
// CRemoteView::ContactAtL
// --------------------------------------------------------------------------
// 
MVPbkSimContact& CRemoteView::ContactAtL( TInt aIndex )
    {
    iCurrentContact->SetL( iSimView.ContactAtL( aIndex ) );
    return *iCurrentContact;
    }

// --------------------------------------------------------------------------
// CRemoteView::ChangeSortOrderL
// --------------------------------------------------------------------------
// 
void CRemoteView::ChangeSortOrderL( const RVPbkSimFieldTypeArray& aSortOrder )
    {
    if ( iSimView.SubSessionHandle() ) 
        {
        SetSortOrderL( aSortOrder );
        iSimView.ChangeSortOrderL( aSortOrder );        
        }
    }

// --------------------------------------------------------------------------
// CRemoteView::MapSimIndexToViewIndexL
// --------------------------------------------------------------------------
// 
TInt CRemoteView::MapSimIndexToViewIndexL( TInt aSimIndex )
    {
    return iSimView.FindViewIndexL( aSimIndex );
    }

// --------------------------------------------------------------------------
// CRemoteView::ContactMatchingPrefixL
// --------------------------------------------------------------------------
//     
MVPbkSimStoreOperation* CRemoteView::ContactMatchingPrefixL(
        const MDesCArray& aFindStrings, 
        MVPbkSimViewFindObserver& aObserver )
    {    
    CViewFindOperation* operation = CViewFindOperation::NewL(
        aFindStrings, aObserver, iSimView, *this );
    operation->ActivateL();
    return operation;
    }

// --------------------------------------------------------------------------
// CRemoteView::SortOrderL
// --------------------------------------------------------------------------
//
const RVPbkSimFieldTypeArray& CRemoteView::SortOrderL() const
    {
    HBufC8* sortOrder = iSimView.SortOrderL();
    CleanupStack::PushL( sortOrder );
    RDesReadStream readStream( *sortOrder );
    readStream.PushL();
    iSortOrder.Reset();
    readStream >> iSortOrder;
    CleanupStack::PopAndDestroy( &readStream );
    CleanupStack::PopAndDestroy( sortOrder );
    return iSortOrder;
    }
    
// --------------------------------------------------------------------------
// CRemoteView::MapSimIndexToViewIndexL
// --------------------------------------------------------------------------
//
void CRemoteView::StoreReady( MVPbkSimCntStore& /*aStore*/ )
    {
    if ( !iSimView.SubSessionHandle() )
        {
        TRAPD( result, iSimView.OpenL( iStore.StoreSession(), iSortOrder, 
            iConstructionPolicy, *iViewName, iFilter ) );
        if (result != KErrNone)
            {
            SendEvent(iObservers, &MVPbkSimViewObserver::ViewError, 
                      *this, result );
            }
        ActivateViewNotification();
        // Cancel any ongoing "View unavailable" events
        iObserverOp->Purge();
        }
    }

// --------------------------------------------------------------------------
// CRemoteView::StoreError
// --------------------------------------------------------------------------
//
void CRemoteView::StoreError( MVPbkSimCntStore& /*aStore*/, TInt aError )
    {
    // Cancel any ongoing view events
    iObserverOp->Purge();
    SendEvent(iObservers, &MVPbkSimViewObserver::ViewError, 
              *this, aError );
    }

// --------------------------------------------------------------------------
// CRemoteView::StoreNotAvailable
// --------------------------------------------------------------------------
//
void CRemoteView::StoreNotAvailable( MVPbkSimCntStore& /*aStore*/ )
    {
    // Cancel any ongoing view events
    iObserverOp->Purge();
    SendEvent(iObservers, &MVPbkSimViewObserver::ViewNotAvailable, *this);
    }

// --------------------------------------------------------------------------
// CRemoteView::StoreNotAvailable
// --------------------------------------------------------------------------
//
void CRemoteView::StoreContactEvent( TEvent /*aEvent*/, TInt /*aSimIndex*/ )
    {
    
    }

// --------------------------------------------------------------------------
// CRemoteView::ActivateViewNotification
// --------------------------------------------------------------------------
// 
void CRemoteView::ActivateViewNotification()
    {
    if ( !IsActive() && iSimView.SubSessionHandle() )
        {
        iSimView.ListenToViewEvents( iStatus, iEventData );
        SetActive();
        }
    }

// --------------------------------------------------------------------------
// CRemoteView::SetSortOrderL
// --------------------------------------------------------------------------
// 
void CRemoteView::SetSortOrderL( const RVPbkSimFieldTypeArray& aSortOrder )
    {
    iSortOrder.Reset();
    const TInt count = aSortOrder.Count();
    for ( TInt i = 0; i < count; ++i )
        {
        iSortOrder.AppendL( aSortOrder[i] );
        }
    }

// --------------------------------------------------------------------------
// CRemoteView::IssueRequest
// --------------------------------------------------------------------------
// 
void CRemoteView::IssueRequest( TInt aError )
    {
    TRequestStatus* status = &iStatus;
    User::RequestComplete(status, aError);
    SetActive();
    }

// --------------------------------------------------------------------------
// CRemoteView::DoViewUnavailableL
// --------------------------------------------------------------------------
// 
void CRemoteView::DoViewUnavailableL( MVPbkSimViewObserver& aObserver )
    {
    aObserver.ViewNotAvailable( *this );
    }

// --------------------------------------------------------------------------
// CRemoteView::DoViewUnavailableError
// --------------------------------------------------------------------------
// 
void CRemoteView::DoViewUnavailableError( MVPbkSimViewObserver& aObserver, 
        TInt aError )
    {
    aObserver.ViewError( *this, aError );
    }
} // namespace VPbkSimStore

//  End of File  
