/*
* 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 single contact data assigner.
*
*/


#include "CPbk2SingleContactDataAssigner.h"

// Phonebook 2
#include "CPbk2ServerAppAppUi.h"
#include "MPbk2UiServiceObserver.h"
#include "TPbk2TitlePaneOperator.h"
#include "TPbk2ServerMessageDataRetriever.h"
#include "CPbk2ServerAppStoreManager.h"
#include "CPbk2SelectSinglePropertyPhase.h"
#include "CPbk2ContactFetchPhase.h"
#include "CPbk2SingleAssignDataPhase.h"
#include "CPbk2SelectCreateNewPropertyPhase.h"
#include "CPbk2PrepareSingleAssignPhase.h"
#include "MPbk2SelectFieldProperty.h"
#include <Pbk2UIControls.rsg>
#include <Pbk2ServerApp.rsg>
#include <CPbk2StoreManager.h>
#include <CPbk2StoreConfiguration.h>
#include <MPbk2ApplicationServices.h>
#include "TPbk2AssignNoteService.h"

// Virtual Phonebook
#include <CVPbkContactManager.h>
#include <CVPbkContactStoreUriArray.h>
#include <MVPbkContactLink.h>
#include <CVPbkFieldTypeSelector.h>
#include <MVPbkStoreContact.h>
#include <TVPbkContactStoreUriPtr.h>
#include <VPbkContactStoreUris.h>

// System includes
#include <AiwContactAssignDataTypes.h>

using namespace AiwContactAssign;


/// Unnamed namespace for local definitions
namespace {

#ifdef _DEBUG

enum TPanicCode
    {
    ELogicPreselectedContacts,
    EPanicLogicPhaseCompletion
    };

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

#endif // _DEBUG

/**
 * Sets title pane.
 *
 * @param aDataRetriever    Server message data retriever.
 * @param aFlags            Assign flags.
 * @param aMessage          Server message.
 */
void SetTitlePaneL
        ( TPbk2ServerMessageDataRetriever& aDataRetriever, TUint aFlags,
          const RMessage2& aMessage )
    {
    HBufC* titlePaneText = NULL;
    if ( !( aFlags & AiwContactAssign::EUseProviderTitle ) )
        {
        titlePaneText = aDataRetriever.GetTitlePaneTextL( aMessage );
        }
    TPbk2TitlePaneOperator titlePaneOperator;
    titlePaneOperator.SetTitlePaneL( titlePaneText ); // takes ownership
    }

} /// namespace


// --------------------------------------------------------------------------
// CPbk2SingleContactDataAssigner::CPbk2SingleContactDataAssigner
// --------------------------------------------------------------------------
//
CPbk2SingleContactDataAssigner::CPbk2SingleContactDataAssigner
        ( MPbk2UiServiceObserver& aObserver ) :
            iObserver( aObserver )
    {
    }

// --------------------------------------------------------------------------
// CPbk2SingleContactDataAssigner::~CPbk2SingleContactDataAssigner
// --------------------------------------------------------------------------
//
CPbk2SingleContactDataAssigner::~CPbk2SingleContactDataAssigner()
    {
    delete iSelectPropertyPhase;
    delete iFetchPhase;
    delete iPrepareAssignPhase;
    delete iAssignDataPhase;
    delete iStoreUris;
    delete iDataBuffer;
    delete iAddressSelectFilterBuffer;
    delete iPreselectedContact;
    delete iSelectFieldProperty;
    delete iContactViewFilter;
    delete iStoreManager;
    }

// --------------------------------------------------------------------------
// CPbk2SingleContactDataAssigner::NewL
// --------------------------------------------------------------------------
//
CPbk2SingleContactDataAssigner* CPbk2SingleContactDataAssigner::NewL
        ( const RMessage2& aFetchCompleteMessage,
          MPbk2UiServiceObserver& aObserver )
    {
    CPbk2SingleContactDataAssigner* self =
        new(ELeave) CPbk2SingleContactDataAssigner( aObserver );
    CleanupStack::PushL( self );
    self->ConstructL( aFetchCompleteMessage );
    CleanupStack::Pop( self );
    return self;
    }

// --------------------------------------------------------------------------
// CPbk2SingleContactDataAssigner::ConstructL
// --------------------------------------------------------------------------
//
void CPbk2SingleContactDataAssigner::ConstructL( const RMessage2& aMessage )
    {
    // Retrieve data from the client-server message
    TPbk2ServerMessageDataRetriever dataRetriever;
    iAssignFlags = dataRetriever.SingleContactAssignFlagsL( aMessage );

    // Set title pane
    SetTitlePaneL( dataRetriever, iAssignFlags, aMessage );

    CPbk2ServerAppAppUi& appUi = static_cast<CPbk2ServerAppAppUi&>
        ( *CEikonEnv::Static()->EikAppUi() );

    iPreselectedContact = dataRetriever.GetPreselectedContactLinksL
        ( aMessage, appUi.ApplicationServices().ContactManager() );
    iStoreUris = dataRetriever.GetContactStoreUriArrayL
        ( aMessage, appUi.ApplicationServices().StoreConfiguration(),
          iPreselectedContact, iUseDeviceConfig );

    // Assert that there aren't multiple preselected contacts
    __ASSERT_DEBUG( ( !iPreselectedContact ||
        iPreselectedContact->Count() <= 1 ),
        Panic( ELogicPreselectedContacts ) );

    iAddressSelectFilterBuffer =
        dataRetriever.GetAddressSelectFilterBufferL( aMessage );
    iDataBuffer = dataRetriever.GetDataBufferL( aMessage );
    iMimeType = dataRetriever.GetMimeTypeL( aMessage );
    iFieldIndex = dataRetriever.GetFocusIndexL( aMessage );

    iEditorHelpContext = dataRetriever.GetEditorHelpContextL( aMessage );

    // Drop all non-writable stores
    iStoreManager = CPbk2ServerAppStoreManager::NewL
        ( appUi.StoreManager(),
          appUi.ApplicationServices().ContactManager() );
    iStoreManager->RemoveReadOnlyStoreUris
        ( *iStoreUris, appUi.ApplicationServices().StoreProperties() );

    // Retrieve view filter
    iContactViewFilter =
        dataRetriever.GetContactViewFilterForAttributeAssignL
            ( aMessage,
              appUi.ApplicationServices().ContactManager().FieldTypes() );
    }

// --------------------------------------------------------------------------
// CPbk2SingleContactDataAssigner::LaunchServiceL
// --------------------------------------------------------------------------
//
void CPbk2SingleContactDataAssigner::LaunchServiceL()
    {
    // Open stores
    iStoreManager->LoadAndOpenContactStoresL( *iStoreUris, *this, ETrue );
    }

// --------------------------------------------------------------------------
// CPbk2SingleContactDataAssigner::CancelService
// --------------------------------------------------------------------------
//
void CPbk2SingleContactDataAssigner::CancelService()
    {
    if ( iAssignDataPhase )
        {
        iAssignDataPhase->CancelServicePhase();
        }

    if ( iPrepareAssignPhase )
        {
        iPrepareAssignPhase->CancelServicePhase();
        }

    if ( iSelectPropertyPhase )
        {
        iSelectPropertyPhase->CancelServicePhase();
        }

    if ( iFetchPhase )
        {
        iFetchPhase->CancelServicePhase();
        }
    }

// --------------------------------------------------------------------------
// CPbk2SingleContactDataAssigner::AcceptDelayedContactsL
// --------------------------------------------------------------------------
//
void CPbk2SingleContactDataAssigner::AcceptDelayedContactsL
        ( const TDesC8& /*aContactLinkBuffer*/ )
    {
    // Do nothing
    }

// --------------------------------------------------------------------------
// CPbk2SingleContactDataAssigner::ExitServiceL
// --------------------------------------------------------------------------
//
void CPbk2SingleContactDataAssigner::ExitServiceL( TInt aExitCommandId )
    {
    if ( iAssignDataPhase )
        {
        iAssignDataPhase->RequestCancelL( aExitCommandId );
        }

    if ( iPrepareAssignPhase )
        {
        iPrepareAssignPhase->RequestCancelL( aExitCommandId );
        }

    if ( iSelectPropertyPhase )
        {
        iSelectPropertyPhase->RequestCancelL( aExitCommandId );
        }

    if ( iFetchPhase )
        {
        iFetchPhase->RequestCancelL( aExitCommandId );
        }
    }

// --------------------------------------------------------------------------
// CPbk2SingleContactDataAssigner::ServiceResults
// --------------------------------------------------------------------------
//
void CPbk2SingleContactDataAssigner::ServiceResults(TServiceResults* aResults) const
    {
    if ( iAssignDataPhase )
        {
        aResults->iLinkArray = iAssignDataPhase->Results();
        aResults->iExtraData = iAssignDataPhase->ExtraResultData();
        aResults->iFieldContent = iAssignDataPhase->FieldContent();
        }
    }

// --------------------------------------------------------------------------
// CPbk2SingleContactDataAssigner::NextPhase
// --------------------------------------------------------------------------
//
void CPbk2SingleContactDataAssigner::NextPhase
        ( MPbk2ServicePhase& aPhase )
    {
    TInt err = KErrNone;

    if ( &aPhase == iFetchPhase )
        {
        MVPbkContactLinkArray* fetchResult = iFetchPhase->Results();
        __ASSERT_DEBUG( fetchResult && fetchResult->Count() > 0,
            Panic( EPanicLogicPhaseCompletion ) );

        TRAP( err, LaunchSelectSinglePropertyPhaseL( fetchResult ) );
        }
    else if ( &aPhase == iSelectPropertyPhase )
        {
        TRAP( err, LaunchPrepareSingleAssignPhaseL
            ( iSelectPropertyPhase->TakeStoreContact() ) );
        }
    else if ( &aPhase == iPrepareAssignPhase )
        {
        TRAP( err, LaunchAssignPhaseL
            ( iPrepareAssignPhase->TakeStoreContact() ) );
        }
    else if ( &aPhase == iAssignDataPhase )
        {
        iObserver.ServiceComplete();
        }
    else
        {
        __ASSERT_DEBUG( EFalse, Panic( EPanicLogicPhaseCompletion ) );
        }

    if ( err != KErrNone )
        {
        iObserver.ServiceError( err );
        }
    }

// --------------------------------------------------------------------------
// CPbk2SingleContactDataAssigner::PreviousPhase
// --------------------------------------------------------------------------
//
void CPbk2SingleContactDataAssigner::PreviousPhase
        ( MPbk2ServicePhase& aPhase )
    {
    TInt err = KErrNone;

    if ( &aPhase == iPrepareAssignPhase )
        {
        MVPbkContactLinkArray* resultLinks = aPhase.Results();
        __ASSERT_DEBUG( resultLinks && resultLinks->Count() == 1,
            Panic( EPanicLogicPhaseCompletion ) );

        TRAP( err, LaunchSelectSinglePropertyPhaseL( resultLinks ) );
        }

    if ( err != KErrNone )
        {
        iObserver.ServiceError( err );
        }
    }

// --------------------------------------------------------------------------
// CPbk2SingleContactDataAssigner::PhaseCanceled
// --------------------------------------------------------------------------
//
void CPbk2SingleContactDataAssigner::PhaseCanceled
        ( MPbk2ServicePhase& /*aPhase*/ )
    {
    iObserver.ServiceCanceled();
    }

// --------------------------------------------------------------------------
// CPbk2SingleContactDataAssigner::PhaseAborted
// --------------------------------------------------------------------------
//
void CPbk2SingleContactDataAssigner::PhaseAborted
        ( MPbk2ServicePhase& /*aPhase*/ )
    {
    iObserver.ServiceAborted();
    }

// --------------------------------------------------------------------------
// CPbk2SingleContactDataAssigner::PhaseError
// --------------------------------------------------------------------------
//
void CPbk2SingleContactDataAssigner::PhaseError
        ( MPbk2ServicePhase& /*aPhase*/, TInt aErrorCode )
    {
    iObserver.ServiceError( aErrorCode );
    }

// --------------------------------------------------------------------------
// CPbk2SingleContactDataAssigner::PhaseOkToExit
// --------------------------------------------------------------------------
//
TBool CPbk2SingleContactDataAssigner::PhaseOkToExit
        ( MPbk2ServicePhase& /*aPhase*/, TInt aCommandId )
    {
    // Deny exit and pass an asynchronous query to the consumer,
    // which may later approve exit
    iObserver.CompleteExitMessage( aCommandId );
    return EFalse;
    }

// --------------------------------------------------------------------------
// CPbk2SingleContactDataAssigner::PhaseAccept
// --------------------------------------------------------------------------
//
void CPbk2SingleContactDataAssigner::PhaseAccept
        ( MPbk2ServicePhase& /*aPhase*/, const TDesC8& /*aMarkedEntries*/,
          const TDesC8& /*aLinkData*/ )
    {
    // Not supported in assign
    }

// --------------------------------------------------------------------------
// CPbk2SingleContactDataAssigner::ContactUiReadyL
// --------------------------------------------------------------------------
//
void CPbk2SingleContactDataAssigner::ContactUiReadyL
        ( MPbk2StartupMonitor& aStartupMonitor )
    {
    aStartupMonitor.DeregisterEvents( *this );
 
   if ( iAssignFlags & ECreateNewContact )
        {        
        CVPbkContactStoreUriArray* validStores =
            iStoreManager->CurrentlyValidStoresL();
        CleanupStack::PushL( validStores );

        CPbk2ServerAppAppUi& appUi = static_cast<CPbk2ServerAppAppUi&>
            ( *CEikonEnv::Static()->EikAppUi() );

        // Saving store URI
        TVPbkContactStoreUriPtr savingStoreUri =
            appUi.ApplicationServices().StoreConfiguration().
                DefaultSavingStoreL();

        TPbk2AssignNoteService noteService;
        if ( validStores->IsIncluded ( savingStoreUri ) )
            {
            LaunchSelectCreateNewPropertyPhaseL( savingStoreUri );
            }
        else if ( noteService.ShowCreateNewToPhoneQueryL() )
            {
            savingStoreUri.Set( 
                TVPbkContactStoreUriPtr( 
                    VPbkContactStoreUris::DefaultCntDbUri() ) );
            LaunchSelectCreateNewPropertyPhaseL( savingStoreUri );
            }
        else
            {
            // Canceled
            iObserver.ServiceCanceled();
            }

        CleanupStack::PopAndDestroy( validStores );
        }
    else
        {
        if ( iPreselectedContact && iPreselectedContact->Count() == 1 )
            {
            if ( iStoreManager->ContactsAvailableL( *iPreselectedContact ) )
                {
                LaunchSelectSinglePropertyPhaseL( iPreselectedContact );
                }
            else
                {
                iObserver.ServiceError( KErrNotSupported );
                }
            }
        else
            {
            LaunchFetchPhaseL();
            }
        }
    }

// --------------------------------------------------------------------------
// CPbk2SingleContactDataAssigner::StartupCanceled
// --------------------------------------------------------------------------
//
void  CPbk2SingleContactDataAssigner::StartupCanceled( TInt aErrorCode )
    {
    if ( aErrorCode == KErrCancel )
        {
        iObserver.ServiceCanceled();
        }
    else
        {
        iObserver.ServiceError( aErrorCode );
        }
    }

// --------------------------------------------------------------------------
// CPbk2SingleContactDataAssigner::LaunchFetchPhaseL
// --------------------------------------------------------------------------
//
void CPbk2SingleContactDataAssigner::LaunchFetchPhaseL()
    {
    CPbk2FetchDlg::TParams params;
    params.iResId = R_PBK2_SINGLE_ENTRY_FETCH_DLG;
    params.iFlags = CPbk2FetchDlg::EFetchSingle;

    delete iFetchPhase;
    iFetchPhase = NULL;
    iFetchPhase = CPbk2ContactFetchPhase::NewL
        ( *this, *iStoreManager, params, ETrue,
          MPbk2FetchDlgObserver::EFetchYes, iContactViewFilter,
          iUseDeviceConfig, iStoreUris );

    CPbk2ServerAppAppUi& appUi = static_cast<CPbk2ServerAppAppUi&>
        ( *CEikonEnv::Static()->EikAppUi() );

    // Change layout to fetch's layout
    appUi.ChangeStatuspaneLayoutL(
        CPbk2ServerAppAppUi::EStatusPaneLayoutUsual );

    iFetchPhase->LaunchServicePhaseL();
    }

// --------------------------------------------------------------------------
// CPbk2SingleContactDataAssigner::LaunchSelectSinglePropertyPhaseL
// --------------------------------------------------------------------------
//
void CPbk2SingleContactDataAssigner::LaunchSelectSinglePropertyPhaseL
        ( MVPbkContactLinkArray* aContactLinks )
    {
    delete iSelectPropertyPhase;
    iSelectPropertyPhase = NULL;

    // Prepare parameters by reseting them
    delete iSelectFieldProperty;
    iSelectFieldProperty = NULL;
    iSelectFieldResult = KErrNotReady;

    iSelectPropertyPhase = CPbk2SelectSinglePropertyPhase::NewL
        ( *this, aContactLinks, iAddressSelectFilterBuffer,
          iSelectFieldProperty, iSelectFieldResult );

    iRelocationFlags = CPbk2ContactRelocator::EPbk2RelocatorExistingContact;

    CPbk2ServerAppAppUi& appUi = static_cast<CPbk2ServerAppAppUi&>
        ( *CEikonEnv::Static()->EikAppUi() );

    // Change layout back to regular
    appUi.ChangeStatuspaneLayoutL(
        CPbk2ServerAppAppUi::EStatusPaneLayoutEmpty );

    iSelectPropertyPhase->LaunchServicePhaseL();
    }

// --------------------------------------------------------------------------
// CPbk2SingleContactDataAssigner::LaunchSelectCreateNewPropertyPhaseL
// --------------------------------------------------------------------------
//
void CPbk2SingleContactDataAssigner::LaunchSelectCreateNewPropertyPhaseL(
        TVPbkContactStoreUriPtr  savingStoreUri )
    {
    delete iSelectPropertyPhase;
    iSelectPropertyPhase = NULL;

    // Prepare parameters by reseting them
    delete iSelectFieldProperty;
    iSelectFieldProperty = NULL;
    iSelectFieldResult = KErrNotReady;

    iSelectPropertyPhase = CPbk2SelectCreateNewPropertyPhase::NewL
        ( savingStoreUri, *this, iAddressSelectFilterBuffer,  
          iSelectFieldProperty, iSelectFieldResult, iInformationNoteFlags );

    iRelocationFlags = CPbk2ContactRelocator::EPbk2RelocatorNewContact;

    CPbk2ServerAppAppUi& appUi = static_cast<CPbk2ServerAppAppUi&>
        ( *CEikonEnv::Static()->EikAppUi() );

    // Change layout back to regular
    appUi.ChangeStatuspaneLayoutL(
        CPbk2ServerAppAppUi::EStatusPaneLayoutEmpty );

    iSelectPropertyPhase->LaunchServicePhaseL();
    }

// --------------------------------------------------------------------------
// CPbk2SingleContactDataAssigner::LaunchPrepareSingleAssignPhaseL
// --------------------------------------------------------------------------
//
void CPbk2SingleContactDataAssigner::LaunchPrepareSingleAssignPhaseL
        ( MVPbkStoreContact* aStoreContact )
    {
    delete iPrepareAssignPhase;
    iPrepareAssignPhase = NULL;

    CleanupStack::PushL( aStoreContact );
    iPrepareAssignPhase = CPbk2PrepareSingleAssignPhase::NewL
        ( *this, aStoreContact, iSelectFieldProperty,
          iSelectFieldResult, iFieldIndex, iInformationNoteFlags,
          iRelocationFlags );
    CleanupStack::Pop( aStoreContact );

    iPrepareAssignPhase->LaunchServicePhaseL();
    }

// --------------------------------------------------------------------------
// CPbk2SingleContactDataAssigner::LaunchAssignPhaseL
// --------------------------------------------------------------------------
//
void CPbk2SingleContactDataAssigner::LaunchAssignPhaseL
        ( MVPbkStoreContact* aStoreContact )
    {
    delete iAssignDataPhase;
    iAssignDataPhase = NULL;

    CleanupStack::PushL( aStoreContact );
    iAssignDataPhase = CPbk2SingleAssignDataPhase::NewL
        ( *this, aStoreContact, iSelectFieldProperty,
          iFieldIndex, iDataBuffer, iMimeType,
          iEditorHelpContext, iAssignFlags, iInformationNoteFlags );
    CleanupStack::Pop( aStoreContact );

    // In case of the assign phase it is important to delete the
    // previous phases so that exit and cancel methods work correctly
    delete iPrepareAssignPhase;
    iPrepareAssignPhase = NULL;
    delete iSelectPropertyPhase;
    iSelectPropertyPhase = NULL;
    delete iFetchPhase;
    iFetchPhase = NULL;

    iAssignDataPhase->LaunchServicePhaseL();
    }

// End of File
