/*
* 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:  Contacts Model store contact view implementation.
*
*/


#include "CViewBase.h"

// INCLUDES

// VPbkCntModel
#include "CContactStore.h"
#include "CFieldFactory.h"
#include "CContact.h"
#include "CFieldTypeList.h"
#include "CContactLink.h"
#include "CContactBookmark.h"
#include "CFindView.h"
#include "VPbkCntModelRemoteViewPreferences.h"
#include "CSortOrderAcquirerList.h"

// VPbkEng
#include <MVPbkContactViewObserver.h>
#include <MVPbkFieldType.h>
#include <VPbkError.h>
#include <CVPbkSortOrder.h>
#include <CVPbkAsyncCallback.h>
#include <VPbkPrivateUid.h>     // KFindPluingUID
#include <VPbkSendEventUtility.h>
#include <CVPbkContactViewDefinition.h>
#include <MVPbkContactStoreProperties.h>

// System includes
#include <cntitem.h>

// Debugging headers
#include <VPbkDebug.h>

namespace VPbkCntModel {

// CONSTANTS

const TInt KObserverArrayGranularity = 4;
    
// --------------------------------------------------------------------------
// CViewBase::CViewBase
// --------------------------------------------------------------------------
//
CViewBase::CViewBase( CContactStore& aParentStore ) :
        iObservers( KObserverArrayGranularity ),
        iParentStore( aParentStore )
    {
    }

// --------------------------------------------------------------------------
// CViewBase::~CViewBase
// --------------------------------------------------------------------------
//
CViewBase::~CViewBase()
    {
    delete iObserverOp;
    delete iFilterObsOp;
    delete iEventLink;
    if (iView)
        {
        iView->Close(*this);
        }
    delete iCurrentContact;
    iObservers.Close();
    iFilteringObservers.Close();
    delete iViewDefinition;
    delete iSortOrder;
    iParentStore.RemoveObserver(*this);
    }

// --------------------------------------------------------------------------
// CViewBase::ConstructL
// --------------------------------------------------------------------------
//
void CViewBase::ConstructL(
        const CVPbkContactViewDefinition& aViewDefinition,
        MVPbkContactViewObserver& aObserver,
        const MVPbkFieldTypeList& aSortOrder )
    {
    iParentStore.AddObserverL(*this);
    iSortOrder = CVPbkSortOrder::NewL(aSortOrder);
    iViewDefinition = CVPbkContactViewDefinition::NewL( aViewDefinition );

    if ( iParentStore.IsOpened() )
        {
        InitializeViewL( aViewDefinition, aSortOrder );
        }

    iObserverOp =
        CVPbkAsyncObjectOperation<MVPbkContactViewObserver>::NewL();
    iFilterObsOp =
        CVPbkAsyncObjectOperation<MFilteredViewSupportObserver>::NewL();

    AddObserverL(aObserver);
    }

// --------------------------------------------------------------------------
// CViewBase::ConstructL
// --------------------------------------------------------------------------
//
void CViewBase::ConstructL(
        const CVPbkContactViewDefinition& aViewDefinition,
        const MVPbkFieldTypeList& aSortOrder )
    {
    iParentStore.AddObserverL(*this);
    iSortOrder = CVPbkSortOrder::NewL(aSortOrder);
    iViewDefinition = CVPbkContactViewDefinition::NewL( aViewDefinition );

    if ( iParentStore.IsOpened() )
        {
        InitializeViewL( aViewDefinition, aSortOrder );
        }

    iObserverOp =
        CVPbkAsyncObjectOperation<MVPbkContactViewObserver>::NewL();
    iFilterObsOp =
        CVPbkAsyncObjectOperation<MFilteredViewSupportObserver>::NewL();
    }

// --------------------------------------------------------------------------
// CViewBase::ChangeSortOrderL
// --------------------------------------------------------------------------
//
void CViewBase::ChangeSortOrderL(const MVPbkFieldTypeList& aSortOrder)
    {
    // If this view is a remote view in Contacts server a strict policy
    // must be applied for changing sortorder. Shared views are used
    // widely in S60 applications so their sortorder must be controlled
    // by S60 Phonebook application.
    LeaveIfIncorrectSortOrderL( aSortOrder );
    
    CVPbkSortOrder* newSortOrder = CVPbkSortOrder::NewL(aSortOrder);
    CleanupStack::PushL(newSortOrder);

    RContactViewSortOrder viewSortOrder = CreateSortOrderL(aSortOrder);
    CleanupClosePushL(viewSortOrder);

    if ( !DoChangeSortOrderL( *iViewDefinition, viewSortOrder ) )
        {
        TeardownView();
        InitializeViewL( *iViewDefinition, aSortOrder );
        }
    
    CleanupStack::PopAndDestroy(); // viewSortOrder
    CleanupStack::Pop(); // newSortOrder

    delete iSortOrder;
    iSortOrder = newSortOrder;
    }

// --------------------------------------------------------------------------
// CViewBase::SortOrder
// --------------------------------------------------------------------------
//
const MVPbkFieldTypeList& CViewBase::SortOrder() const
    {
    return *iSortOrder;
    }

// --------------------------------------------------------------------------
// CViewBase::RefreshL
// --------------------------------------------------------------------------
//
void CViewBase::RefreshL()
    {
    // make the view sort itself again to refresh contents
    RContactViewSortOrder viewSortOrder = CreateSortOrderL(*iSortOrder);
    CleanupClosePushL(viewSortOrder);

    DoChangeSortOrderL( *iViewDefinition, viewSortOrder );

    CleanupStack::PopAndDestroy(); // viewSortOrder
    }

// --------------------------------------------------------------------------
// CViewBase::ContactCountL
// --------------------------------------------------------------------------
//
TInt CViewBase::ContactCountL() const
    {
    TInt result = 0;
    if (iViewReady)
        {
        result = iView->CountL();
        }
    return result;
    }

// --------------------------------------------------------------------------
// CViewBase::ContactAtL
// --------------------------------------------------------------------------
//
const MVPbkViewContact& CViewBase::ContactAtL(TInt aIndex) const
    {
    __ASSERT_ALWAYS( aIndex >= 0,
        VPbkError::Panic( VPbkError::EInvalidContactIndex ) );
    if ( aIndex >= ContactCountL() )
        {
        User::Leave( KErrArgument );
        }

    const ::CViewContact& viewContact = iView->ContactAtL(aIndex);
    iCurrentContact->SetViewContact(viewContact);
    return *iCurrentContact;
    }

// --------------------------------------------------------------------------
// CViewBase::CreateLinkLC
// --------------------------------------------------------------------------
//
MVPbkContactLink* CViewBase::CreateLinkLC(TInt aIndex) const
    {
    __ASSERT_ALWAYS( aIndex >= 0,
        VPbkError::Panic( VPbkError::EInvalidContactIndex ) );
    if ( aIndex >= ContactCountL() )
        {
        User::Leave( KErrArgument );
        }

    TContactItemId contactId = iView->AtL(aIndex);
    return CContactLink::NewLC(iParentStore, contactId);
    }

// --------------------------------------------------------------------------
// CViewBase::IndexOfLinkL
// --------------------------------------------------------------------------
//
TInt CViewBase::IndexOfLinkL(const MVPbkContactLink& aContactLink) const
    {
    TInt result = KErrNotFound;

    if (&aContactLink.ContactStore() == &ContactStore())
        {
        const CContactLink& link = static_cast<const CContactLink&>(aContactLink);
        result = iView->FindL(link.ContactId());
        }

    return result;
    }

// --------------------------------------------------------------------------
// CViewBase::AddObserverL
// --------------------------------------------------------------------------
//
void CViewBase::AddObserverL(MVPbkContactViewObserver& aObserver)
    {
    CVPbkAsyncObjectCallback<MVPbkContactViewObserver>* callback =
        VPbkEngUtils::CreateAsyncObjectCallbackLC(
            *this,
            &CViewBase::DoAddObserverL,
            &CViewBase::AddObserverError,
            aObserver);
    iObserverOp->CallbackL( callback );
    CleanupStack::Pop( callback );

    /// Insert to first position because event are send in reverse order.
    /// Last inserted gets notifcation last.
    iObservers.InsertL( &aObserver, 0 );
    }

// --------------------------------------------------------------------------
// CViewBase::RemoveObserver
// --------------------------------------------------------------------------
//
void CViewBase::RemoveObserver(MVPbkContactViewObserver& aObserver)
    {
    iObserverOp->CancelCallback( &aObserver );
    const TInt index( iObservers.Find( &aObserver ) );
    if (index != KErrNotFound)
        {
        iObservers.Remove(index);
        }
    }

// --------------------------------------------------------------------------
// CViewBase::MatchContactStore
// --------------------------------------------------------------------------
//
TBool CViewBase::MatchContactStore(const TDesC& aContactStoreUri) const
    {
    return iParentStore.MatchContactStore(aContactStoreUri);
    }

// --------------------------------------------------------------------------
// CViewBase::MatchContactStoreDomain
// --------------------------------------------------------------------------
//
TBool CViewBase::MatchContactStoreDomain
        ( const TDesC& aContactStoreDomain ) const
    {
    return iParentStore.MatchContactStoreDomain( aContactStoreDomain );
    }

// --------------------------------------------------------------------------
// CViewBase::CreateBookmarkLC
// --------------------------------------------------------------------------
//
MVPbkContactBookmark* CViewBase::CreateBookmarkLC(TInt aIndex) const
    {
    __ASSERT_ALWAYS( aIndex >= 0,
        VPbkError::Panic( VPbkError::EInvalidContactIndex ) );

    TContactItemId contactId = iView->AtL(aIndex);
    // Link implements also the bookmark interface in this store
    return CContactBookmark::NewLC( contactId, iParentStore );
    }

// --------------------------------------------------------------------------
// CViewBase::IndexOfBookmarkL
// --------------------------------------------------------------------------
//
TInt CViewBase::IndexOfBookmarkL(
        const MVPbkContactBookmark& aContactBookmark) const
    {
    TInt result = KErrNotFound;
    // Bookmark is implemeted as a link in this store
    const CContactBookmark* bookmark =
        dynamic_cast<const CContactBookmark*>(&aContactBookmark);
    if (bookmark &&
        &bookmark->ContactStore() == &ContactStore() )
        {
        result = iView->FindL( bookmark->ContactId() );
        }

    return result;
    }

// --------------------------------------------------------------------------
// CViewBase::AddFilteringObserverL
// --------------------------------------------------------------------------
//
void CViewBase::AddFilteringObserverL(
        MFilteredViewSupportObserver& aObserver )
    {
    // Insert observer in callback function. That ensures that the observer
    // will always get the event asynchronously.

    CVPbkAsyncObjectCallback<MFilteredViewSupportObserver>* callback =
        VPbkEngUtils::CreateAsyncObjectCallbackLC(
            *this,
            &CViewBase::DoAddFilteringObserverL,
            &CViewBase::DoAddFilteringObserverError,
            aObserver);

    iFilterObsOp->CallbackL( callback );
    CleanupStack::Pop( callback );
    }

// --------------------------------------------------------------------------
// CViewBase::RemoveFilteringObserver
// --------------------------------------------------------------------------
//
void CViewBase::RemoveFilteringObserver(
        MFilteredViewSupportObserver& aObserver )
    {
    iFilterObsOp->CancelCallback( &aObserver );
    const TInt index( iFilteringObservers.Find( &aObserver ) );
    if ( index != KErrNotFound )
        {
        iFilteringObservers.Remove( index );
        }
    }

// --------------------------------------------------------------------------
// CViewBase::ViewFiltering
// --------------------------------------------------------------------------
//
MVPbkContactViewFiltering* CViewBase::ViewFiltering()
    {
    // Both contact view and group view support filtering
    return this;
    }

// --------------------------------------------------------------------------
// CViewBase::CreateFilteredViewLC
// --------------------------------------------------------------------------
//
MVPbkContactViewBase* CViewBase::CreateFilteredViewLC(
        MVPbkContactViewObserver& aObserver,
        const MDesCArray& aFindWords,
        const MVPbkContactBookmarkCollection* aAlwaysIncludedContacts )
    {
    CFindView* findView = CFindView::NewLC( aFindWords, *this, aObserver,
            aAlwaysIncludedContacts, Store().ContactStoreDomainFsSession() );
    findView->ActivateContactMatchL();
    return findView;
    }

// --------------------------------------------------------------------------
// CViewBase::UpdateFilterL
// --------------------------------------------------------------------------
//
void CViewBase::UpdateFilterL(
        const MDesCArray& /*aFindWords*/,
        const MVPbkContactBookmarkCollection* /*aAlwaysIncludedContacts*/ )
    {
    // CViewBase implementations are "all contacts" views and not itself
    // filtered views. Only creating a filtered view is supported.
    User::Leave( KErrNotSupported );
    }

// --------------------------------------------------------------------------
// CViewBase::ParentObject
// --------------------------------------------------------------------------
//
MVPbkObjectHierarchy& CViewBase::ParentObject() const
    {
    return iParentStore;
    }

// --------------------------------------------------------------------------
// CViewBase::StoreReady
// --------------------------------------------------------------------------
//
void CViewBase::StoreReady( MVPbkContactStore& /*aContactStore*/ )
    {
    if ( !iViewReady )
        {
        TeardownView();
        TRAPD( error, InitializeViewL( *iViewDefinition, *iSortOrder ) );

        if ( error != KErrNone )
            {
            iViewReady = EFalse;
            SendViewErrorEvent( error );
            }
        }
    }

// --------------------------------------------------------------------------
// CViewBase::StoreUnavailable
// --------------------------------------------------------------------------
//
void CViewBase::StoreUnavailable
        ( MVPbkContactStore& /*aContactStore*/, TInt /*aReason*/ )
    {
    TeardownView();
    iViewReady = EFalse;
    SendViewStateEvent();
    }

// --------------------------------------------------------------------------
// CViewBase::HandleStoreEventL
// --------------------------------------------------------------------------
//
void CViewBase::HandleStoreEventL(
        MVPbkContactStore& /*aContactStore*/,
        TVPbkContactStoreEvent /*aStoreEvent*/)
    {
    // No need to handle this here, events are received from the view
    }

// --------------------------------------------------------------------------
// CViewBase::HandleContactViewEvent
// --------------------------------------------------------------------------
//
void CViewBase::HandleContactViewEvent
        ( const CContactViewBase& /*aView*/,
          const TContactViewEvent& aEvent )
    {
    switch ( aEvent.iEventType )
        {
        case TContactViewEvent::EUnavailable:
            {
            VPBK_DEBUG_PRINT(VPBK_DEBUG_STRING
                ("CViewBase::HandleContactViewEvent(0x%x) EUnavailable"),
                this );

            iViewReady = EFalse;
            SendViewStateEvent();
            break;
            }
        case TContactViewEvent::EReady:
            {
            VPBK_DEBUG_PRINT(VPBK_DEBUG_STRING
                ("CViewBase::HandleContactViewEvent(0x%x) EReady"),
                this);

            iViewReady = ETrue;
            SendViewStateEvent();
            break;
            }
        case TContactViewEvent::EItemAdded:
            {
            VPBK_DEBUG_PRINT(VPBK_DEBUG_STRING
                ("CViewBase::HandleContactViewEvent(0x%x) EItemAdded\
                 index %d id %d"), this, aEvent.iInt, aEvent.iContactId);
            iViewReady = ETrue;
            iEventLink->SetContactId(aEvent.iContactId);
            VPbkEng::SendViewEventToObservers( *this, aEvent.iInt, *iEventLink,
                iObservers, &MVPbkContactViewObserver::ContactAddedToView,
                &MVPbkContactViewObserver::ContactViewError );
            VPbkEng::SendViewEventToObservers( *this, aEvent.iInt, *iEventLink,
                iFilteringObservers,
                &MVPbkContactViewObserver::ContactAddedToView,
                &MVPbkContactViewObserver::ContactViewError );
            break;
            }
        case TContactViewEvent::EItemRemoved:
            {
            VPBK_DEBUG_PRINT(VPBK_DEBUG_STRING
                ("CViewBase::HandleContactViewEvent(0x%x) EItemRemoved\
                index %d id %d"),
                this, aEvent.iInt, aEvent.iContactId);

            iViewReady = ETrue;
            iEventLink->SetContactId( aEvent.iContactId );
            VPbkEng::SendViewEventToObservers( *this, aEvent.iInt, *iEventLink,
                iObservers,
                &MVPbkContactViewObserver::ContactRemovedFromView,
                &MVPbkContactViewObserver::ContactViewError );
            VPbkEng::SendViewEventToObservers( *this, aEvent.iInt, *iEventLink,
                iFilteringObservers,
                &MVPbkContactViewObserver::ContactRemovedFromView,
                &MVPbkContactViewObserver::ContactViewError );
            break;
            }
        case TContactViewEvent::ESortOrderChanged:
            {
            VPBK_DEBUG_PRINT(VPBK_DEBUG_STRING
                ("CViewBase::HandleContactViewEvent(0x%x) ESortOrderChanged"),
                this);

            iViewReady = ETrue;
            // Update the new sort order to the view contact
            TRAPD( res, DoUpdateTypeListL() );
            if ( res != KErrNone )
                {
                SendViewErrorEvent( res );
                }
            else
                {
                SendViewStateEvent();
                }
            break;
            }
        case TContactViewEvent::ESortError:
            {
            VPBK_DEBUG_PRINT(VPBK_DEBUG_STRING
                ("CViewBase::HandleContactViewEvent(0x%x) ESortError"),
                this);

            iViewReady = EFalse;
            SendViewErrorEvent( aEvent.iInt );
            break;
            }
        case TContactViewEvent::EServerError:
            {
            VPBK_DEBUG_PRINT(VPBK_DEBUG_STRING
                ("CViewBase::HandleContactViewEvent(0x%x) EServerError"),
                this);

            iViewReady = EFalse;
            SendViewErrorEvent( aEvent.iInt );
            break;
            }

        case TContactViewEvent::EIndexingError:
            {
            VPBK_DEBUG_PRINT(VPBK_DEBUG_STRING
                ("CViewBase::HandleContactViewEvent(0x%x) EIndexingError"),
                this);

            iViewReady = EFalse;
            SendViewErrorEvent( aEvent.iInt );
            break;
            }
        case TContactViewEvent::EGroupChanged: // FALLTHROUGH
            {
            VPBK_DEBUG_PRINT(VPBK_DEBUG_STRING
                ("CViewBase::HandleContactViewEvent(0x%x) EGroupChanged"),
                this);

            // We don't send any events because EItemRemoved and/or
            // EItemAdded events are generated and those handle the UI
            // refreshing. If the view is not ready we are expecting
            // EReady event from CntModel to refresh the view.
            }
        default:
            {
            // Default is: do nothing
            VPBK_DEBUG_PRINT(VPBK_DEBUG_STRING
                ("CViewBase::HandleContactViewEvent(0x%x) eventType %d"),
                this, aEvent.iEventType );
            break;
            }
        }
    }

// --------------------------------------------------------------------------
// CViewBase::HandleCustomContactViewEvent
// --------------------------------------------------------------------------
//
void CViewBase::HandleCustomContactViewEvent
        ( const CContactViewBase& aView,
          const TContactViewEvent& aEvent )
    {
    VPBK_DEBUG_PRINT(VPBK_DEBUG_STRING
        ("CViewBase::HandleCustomContactViewEvent(0x%x)"), &aView);

    // This function needs to behave like HandleContactViewEvent function
    // above, but without notifying observers. The observers will be notified
    // later, with the succeeding HandleContactViewEvent call.
    switch ( aEvent.iEventType )
        {
        case TContactViewEvent::EReady:             // FALLTHROUGH
        case TContactViewEvent::EItemAdded:         // FALLTHROUGH
        case TContactViewEvent::EItemRemoved:       // FALLTHROUGH
        case TContactViewEvent::ESortOrderChanged:  // FALLTHROUGH
        case TContactViewEvent::EGroupChanged:      // FALLTHROUGH
            {
            iViewReady = ETrue;
            break;
            }

        case TContactViewEvent::EUnavailable:       // FALLTHROUGH
        case TContactViewEvent::ESortError:         // FALLTHROUGH
        case TContactViewEvent::EServerError:       // FALLTHROUGH
        case TContactViewEvent::EIndexingError:     // FALLTHROUGH
            {
            iViewReady = EFalse;
            break;
            }
        default:
            {
            // Do nothing
            break;
            }
        }
    }

// --------------------------------------------------------------------------
// CViewBase::CreateSortOrderL
// --------------------------------------------------------------------------
//
RContactViewSortOrder CViewBase::CreateSortOrderL
        ( const MVPbkFieldTypeList& aSortOrder )
    {
    RContactViewSortOrder sortOrder;
    CleanupClosePushL(sortOrder);

    const TInt count = aSortOrder.FieldTypeCount();
    for (TInt i = 0; i < count; ++i)
        {
        const MVPbkFieldType& fieldType = aSortOrder.FieldTypeAt(i);
        // Ignores all field types that are not supported by this store
        const CContactItemField* field =
            iParentStore.FieldFactory().FindField(fieldType);
        if (field)
            {
            sortOrder.AppendL(field->ContentType().FieldType(0));
            }
        }
    CleanupStack::Pop(); // sortOrder

    return sortOrder;
    }

// --------------------------------------------------------------------------
// CViewBase::DoUpdateTypeListL
// --------------------------------------------------------------------------
//
void CViewBase::DoUpdateTypeListL()
    {
    MVPbkFieldTypeList* typeList = CFieldTypeList::NewLC
        (iView->SortOrderL(), iParentStore.FieldTypeMap());
    iCurrentContact->SetTypeListL(*typeList);

    CVPbkSortOrder* sortOrder = CVPbkSortOrder::NewL(*typeList);
    delete iSortOrder;
    iSortOrder = sortOrder;
    CleanupStack::PopAndDestroy(); // typeList
    }

// --------------------------------------------------------------------------
// CViewBase::DoAddObserverL
// --------------------------------------------------------------------------
//
void CViewBase::DoAddObserverL(MVPbkContactViewObserver& aObserver)
    {
    // Check if aObserver is still observer of this view
    if ( iObservers.Find( &aObserver ) != KErrNotFound )
        {
        if (iViewReady)
            {
            // If this view is ready and there was no error,
            // tell it to the observer
            aObserver.ContactViewReady(*this);
            }
        else if (!iViewReady && !iParentStore.IsOpened())
            {
            aObserver.ContactViewUnavailable(*this);
            }
        // If this view was not ready and there was no error, observer will
        // be called back in HandleContactViewEvent
        }
    }

// --------------------------------------------------------------------------
// CViewBase::AddObserverError
// --------------------------------------------------------------------------
//
void CViewBase::AddObserverError(MVPbkContactViewObserver& aObserver, TInt aError)
    {
    // Check if aObserver is still observer of this view
    if ( iObservers.Find( &aObserver ) != KErrNotFound)
        {
        aObserver.ContactViewError(*this, aError, EFalse);
        }
    }

// --------------------------------------------------------------------------
// CViewBase::DoAddFilteringObserverL
// --------------------------------------------------------------------------
//
void CViewBase::DoAddFilteringObserverL(
        MFilteredViewSupportObserver& aObserver )
    {
    /// Insert to first position because event are send in reverse order.
    /// Last inserted gets notifcation last.
    iFilteringObservers.InsertL( &aObserver, 0 );

    if (iViewReady)
        {
        // If this view is ready and there was no error.
        // Build filtered view first using the internal interface
        aObserver.ContactViewReadyForFiltering( *this );
        // Then let the filtered view to send event to its external
        // observers.
        aObserver.ContactViewReady( *this );
        }
    else if (!iViewReady && !iParentStore.IsOpened())
        {
        aObserver.ContactViewUnavailableForFiltering( *this );
        aObserver.ContactViewUnavailable( *this );
        }
    }

// --------------------------------------------------------------------------
// CViewBase::DoAddFilteringObserverError
// --------------------------------------------------------------------------
//
void CViewBase::DoAddFilteringObserverError(
        MFilteredViewSupportObserver& aObserver, TInt aError )
    {
    // See DoAddFilteringObserverL. If it leaves then adding the aObserver
    // failed.
    aObserver.ContactViewError(*this, aError, EFalse);
    }

// --------------------------------------------------------------------------
// CViewBase::InitializeViewL
// --------------------------------------------------------------------------
//
void CViewBase::InitializeViewL( 
        const CVPbkContactViewDefinition& aViewDefinition,
        const MVPbkFieldTypeList& aSortOrder )
    {
    iCurrentContact = CViewContact::NewL( *this, aSortOrder );

    RContactViewSortOrder viewSortOrder = CreateSortOrderL( aSortOrder );
    CleanupClosePushL( viewSortOrder );

    // Let sub class create the concrete view to iView
    DoInitializeViewL( aViewDefinition, viewSortOrder );
    // Update sort order because shared view can have a different
    // sort order compared to aSortOrder. Creating a new remote view
    // handle to Contacts Model shared view doesn't change the sort order
    // in Contacts Server shared view.
    if ( iView )
        {
        DoUpdateTypeListL();
    
        // Set find plugin uid, without this cntmodel find does not work with
        // all variants.
        iView->SetViewFindConfigPlugin( TUid::Uid( KFindPluginUID ) );
        }

    CleanupStack::PopAndDestroy(); // viewSortOrder

    iEventLink = CContactLink::NewLC( iParentStore, KNullContactId );
    CleanupStack::Pop( iEventLink );
    }

// --------------------------------------------------------------------------
// CViewBase::TeardownView
// --------------------------------------------------------------------------
//
void CViewBase::TeardownView()
    {
    delete iCurrentContact;
    iCurrentContact = NULL;

    if (iView)
        {
        iView->Close(*this);
        iView = NULL;
        }

    delete iEventLink;
    iEventLink = NULL;

    DoTeardownView();
    }

// --------------------------------------------------------------------------
// CViewBase::SendViewErrorEvent
// --------------------------------------------------------------------------
//
void CViewBase::SendViewErrorEvent( TInt aError )
    {
    // Cancel async operation to avoid double message sending
    // to observer in DoAddObserverL
    PurgeAsyncOperations();

    /// Then report the failure to client so that in handle it.
    TBool errorIsNotified = EFalse;
    VPbkEng::SendEventToObservers( *this, aError, errorIsNotified,
        iObservers, &MVPbkContactViewObserver::ContactViewError );
    VPbkEng::SendEventToObservers( *this, aError, errorIsNotified,
        iFilteringObservers, &MVPbkContactViewObserver::ContactViewError );
    }

// --------------------------------------------------------------------------
// CViewBase::SendViewStateEvent
// --------------------------------------------------------------------------
//
void CViewBase::SendViewStateEvent()
    {
    // Cancel async operation to avoid double message sending
    // to observer in DoAddObserverL
    PurgeAsyncOperations();

    void (MVPbkContactViewObserver::*obsNotifyFunc)(
            MVPbkContactViewBase&) =
                &MVPbkContactViewObserver::ContactViewReady;
    void (MFilteredViewSupportObserver::*filtObsNotifyFunc)(
            MParentViewForFiltering&) =
                &MFilteredViewSupportObserver::ContactViewReadyForFiltering;

    if ( !iViewReady )
        {
        obsNotifyFunc = &MVPbkContactViewObserver::ContactViewUnavailable;
        filtObsNotifyFunc =
            &MFilteredViewSupportObserver::ContactViewUnavailableForFiltering;
        }

    // Due to filtered view stack it must be ensured that internal filtered
    // views know first about changes because CRefineViews have pointers to
    // contacts that must not be invalidated.
    // On the other hand the events to external observers must come
    // first from lowest view in the view stack.
    // See MVPbkContactViewFiltering interface.
    VPbkEng::SendViewEventToObservers( *this, iFilteringObservers,
        filtObsNotifyFunc, &MVPbkContactViewObserver::ContactViewError );
    VPbkEng::SendViewEventToObservers( *this, iObservers,
        obsNotifyFunc, &MVPbkContactViewObserver::ContactViewError );
    VPbkEng::SendViewEventToObservers( *this, iFilteringObservers,
        obsNotifyFunc, &MVPbkContactViewObserver::ContactViewError );
    }

// --------------------------------------------------------------------------
// CViewBase::PurgeAsyncOperations
// --------------------------------------------------------------------------
//
void CViewBase::PurgeAsyncOperations()
    {
    // Purge only iObserverOp callbacks because observers are added
    // already in AddObserverL. iFilterObsOp must not be purged because
    // filtering observers are added in a call back DoAddFilteringObserverL.
    iObserverOp->Purge();
    }

// --------------------------------------------------------------------------
// CViewBase::LeaveIfIncorrectSortOrderL
// --------------------------------------------------------------------------
//
void CViewBase::LeaveIfIncorrectSortOrderL( 
        const MVPbkFieldTypeList& aSortOrder )
    {
    if ( RemoteViewDefinition( *iViewDefinition ) )
        {
        // Get allowed sort orders via ECOM
        CVPbkSortOrderAcquirer::TSortOrderAcquirerParam param(
            iParentStore.MasterFieldTypeList() );
        CSortOrderAcquirerList* ecomList = 
                CSortOrderAcquirerList::NewLC(param);
    
        const TInt count = ecomList->Count();
        for ( TInt i = 0; i < count; ++i )
            {
            CVPbkSortOrderAcquirer& acquirer = ecomList->At( i );
            // Sort order is incorrect if
            // 1) acquirer is for this store
            // 2) this is a shared view and acquirer is for the
            //    same named view.
            // 3) aSortOrder is not same as acquirer's sort order.
            if ( acquirer.ApplySortOrderToStoreL( 
                    iParentStore.StoreProperties().Uri() ) &&
                 ecomList->FindInfo(acquirer)->DisplayName().CompareC(
                    RemoteViewName( *iViewDefinition ) ) == 0 &&
                 !VPbkFieldTypeList::IsSame( acquirer.SortOrder(), 
                    aSortOrder) )
                {
                User::Leave( KErrArgument );
                }
            }
        CleanupStack::PopAndDestroy( ecomList );
        }
    }
} // namespace VPbkCntModel

// End of File
