/*
* Copyright (c) 2008 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:  Implementation of the class CPbkxRclContactUpdater.
*
*/


#include "emailtrace.h"
#include <pbk2rclengine.rsg>
#include <CPbkSingleEntryFetchDlg.h>
#include <CPbkContactEngine.h>
#include <CPbkMemoryEntryAddItemDlg.h>
#include <StringLoader.h>
#include <CPbkFieldInfo.h>
#include <CPbkFieldsInfo.h>
#include <aknnotedialog.h>
#include <coemain.h>
#include <data_caging_path_literals.hrh>
#include <bautils.h>

#include "cpbkxrclcontactupdater.h"
#include "pbkxrclutils.h"
#include "pbkxrclengineconstants.h"
#include "pbkxremotecontactlookuppanic.h"

// Local constants
_LIT(KPbkRomFileDrive, "z:");
_LIT(KPbkViewResourceFile, "PbkView.rsc");

// ======== MEMBER FUNCTIONS ========

// ---------------------------------------------------------------------------
// CPbkxRclContactUpdater::NewL
// ---------------------------------------------------------------------------
//
CPbkxRclContactUpdater* CPbkxRclContactUpdater::NewL(
    CPbkContactEngine& aEngine )
    {
    FUNC_LOG;
    CPbkxRclContactUpdater* updater = CPbkxRclContactUpdater::NewLC( aEngine );
    CleanupStack::Pop( updater );
    return updater;
    }

// ---------------------------------------------------------------------------
// CPbkxRclContactUpdater::NewLC
// ---------------------------------------------------------------------------
//
CPbkxRclContactUpdater* CPbkxRclContactUpdater::NewLC(
    CPbkContactEngine& aEngine )
    {
    FUNC_LOG;
    CPbkxRclContactUpdater* updater = 
        new ( ELeave ) CPbkxRclContactUpdater( aEngine );
    CleanupStack::PushL( updater );
    updater->ConstructL();
    return updater;
    }

// ---------------------------------------------------------------------------
// CPbkxRclContactUpdater::CPbkxRclContactUpdater
// ---------------------------------------------------------------------------
//
CPbkxRclContactUpdater::CPbkxRclContactUpdater( CPbkContactEngine& aEngine ) :
    CBase(), iEngine( aEngine )
    {
    FUNC_LOG;
    }

// ---------------------------------------------------------------------------
// CPbkxRclContactUpdater::~CPbkxRclContactUpdater
// ---------------------------------------------------------------------------
//
CPbkxRclContactUpdater::~CPbkxRclContactUpdater()
    {
    FUNC_LOG;
    CCoeEnv::Static()->DeleteResourceFile( iResourceFileOffset );
    }

// ---------------------------------------------------------------------------
// CPbkxRclContactUpdater::ConstructL
// ---------------------------------------------------------------------------
//
void CPbkxRclContactUpdater::ConstructL()
    {
    FUNC_LOG;

    // First load Phonebook resource file so that dialog will find resources
    CCoeEnv* coeEnv = CCoeEnv::Static();
    TFileName resourceFile;
    resourceFile.Copy( KPbkRomFileDrive );
    resourceFile.Append( KDC_RESOURCE_FILES_DIR );
    resourceFile.Append( KPbkViewResourceFile );    
    
    BaflUtils::NearestLanguageFile( coeEnv->FsSession(), resourceFile );
    
    TRAPD( status,
            iResourceFileOffset = coeEnv->AddResourceFileL( resourceFile ) );
    
    if( status != KErrNone )
        {
        PbkxRclPanic( EPbkxRclPanicGeneral );       
        }
    else 
        {
        }
    }

// ---------------------------------------------------------------------------
// CPbkxRclContactUpdater::UpdateContactL
// ---------------------------------------------------------------------------
//
HBufC* CPbkxRclContactUpdater::UpdateContactL( TPbkContactItemField& aField )
    {
    FUNC_LOG;

    // first ask user to select the contact in which the field is added
    CPbkSingleEntryFetchDlg::TParams params;
    params.iContactView = &iEngine.AllContactsView();

    CPbkSingleEntryFetchDlg* fetchDlg = CPbkSingleEntryFetchDlg::NewL( params );
    fetchDlg->ResetWhenDestroyed( &fetchDlg );
    TInt res = 0;
    res = fetchDlg->ExecuteLD();

    CPbkContactItem* contactItem = NULL;
    HBufC* text = NULL;
    if ( res != 0 && params.iSelectedEntry != KNullContactId )
        {
        contactItem = iEngine.OpenContactL( params.iSelectedEntry );
        CleanupStack::PushL( contactItem );
        
        CPbkFieldInfo& fieldInfo = aField.FieldInfo();
        TPbkContactItemField* field = NULL;
        if ( fieldInfo.Multiplicity() == EPbkFieldMultiplicityOne )
            {
            // there can be only one field of this type. query user to select
            // a field in which data is to be saved
            field = SelectUpdatedFieldL( *contactItem, fieldInfo );
            }
        else
            {
            // add new field to contact
            field = &( contactItem->AddFieldL( aField.FieldInfo() ) );
            }
        
        if ( field != NULL )
            {
            if ( field->StorageType() == KStorageTypeText )
                {
                field->TextStorage()->SetTextL( aField.Text() );
                }
            else if ( field->StorageType() == KStorageTypeDateTime )
                {
                field->DateTimeStorage()->SetTime( aField.Time() );
                }
            iEngine.CommitContactL( *contactItem );
            // build string returned to the caller
            text = ConstructUpdatedTextL( *contactItem, *field );
            }
        else
            {
            iEngine.CloseContactL( contactItem->Id() );
            }
        
        CleanupStack::PopAndDestroy( contactItem );
        }
    return text;
    }

// ---------------------------------------------------------------------------
// CPbkxRclContactUpdater::SelectUpdatedFieldL
// ---------------------------------------------------------------------------
//
TPbkContactItemField* CPbkxRclContactUpdater::SelectUpdatedFieldL(
    CPbkContactItem& aContactItem,
    CPbkFieldInfo& aFieldInfo )
    {
    FUNC_LOG;
    TPbkContactItemField* retField = NULL;
    TInt fieldCount = 0;
    CPbkFieldInfo* info = SelectFieldL( aFieldInfo, fieldCount );
    while ( info != NULL && retField == NULL )
        {
        retField = aContactItem.AddOrReturnUnusedFieldL( *info );
        // iterate until user selects field or cancels
        if ( retField == NULL )
            {
            // there is already given field. ask user if it is ok to replace
            // existing data
            HBufC* dlgText = StringLoader::LoadLC( 
                R_QTN_RCL_REPLACE_EXISTING_DETAIL_NOTE,
                info->FieldName() );
            CAknNoteDialog* dialog = new ( ELeave ) CAknNoteDialog();
            dialog->PrepareLC( R_RCL_CONFIRMATION_NOTE_YES_CANCEL );
            dialog->SetTextL( *dlgText );
            
            if ( dialog->RunLD() )
                {
                retField = aContactItem.FindField( *info );
                }
            else
                {
                // user cancelled dialog
                if ( fieldCount > 1 )
                    {
                    // show select field dialog again
                    info = SelectFieldL( aFieldInfo, fieldCount );
                    }
                else
                    {
                    // exit the loop because user refused to update existing 
                    // field and there are no other choices for the fields
                    // to be updated
                    info = NULL;
                    }
                }
            CleanupStack::PopAndDestroy( dlgText );
            }
        }
    return retField;
    }

// ---------------------------------------------------------------------------
// CPbkxRclContactUpdater::ConstructUpdatedTextL
// ---------------------------------------------------------------------------
//
HBufC* CPbkxRclContactUpdater::ConstructUpdatedTextL(
    CPbkContactItem& aContactItem,
    TPbkContactItemField& aField )
    {
    FUNC_LOG;

    HBufC* firstName = PbkxRclUtils::FieldTextL( 
        &aContactItem, 
        EPbkFieldIdFirstName );
    CleanupStack::PushL( firstName );
    
    HBufC* lastName = PbkxRclUtils::FieldTextL( 
        &aContactItem, 
        EPbkFieldIdLastName );
    CleanupStack::PushL( lastName );
    
    RBuf name;
    CleanupClosePushL( name );
    // +1 comes for the space in the format
    name.CreateL( firstName->Length() + lastName->Length() + 1 );
    
    name.Format( KNameFormat, firstName, lastName );
           
    CDesCArrayFlat* textArray = 
        new ( ELeave ) CDesCArrayFlat( KArrayGranularity );
    CleanupStack::PushL( textArray );
    textArray->AppendL( aField.FieldInfo().FieldName() );
    textArray->AppendL( name );
    
    HBufC* text = StringLoader::LoadL( 
        R_QTN_RCL_UPDATE_NOTE,
        *textArray );
    
    CleanupStack::PopAndDestroy( textArray );
    CleanupStack::PopAndDestroy( &name );
    CleanupStack::PopAndDestroy( lastName );
    CleanupStack::PopAndDestroy( firstName );
    
    return text;
    }

// ---------------------------------------------------------------------------
// CPbkxRclContactUpdater::SelectFieldL
// ---------------------------------------------------------------------------
//
CPbkFieldInfo* CPbkxRclContactUpdater::SelectFieldL(
    CPbkFieldInfo& aFieldInfo,
    TInt& aFieldCount )
    {
    FUNC_LOG;
    // construct possible field types
    const CPbkFieldsInfo& fields = iEngine.FieldsInfo();
    CArrayPtrFlat<CPbkFieldInfo>* fieldArray = 
        new ( ELeave ) CArrayPtrFlat<CPbkFieldInfo>( KArrayGranularity );
    CleanupStack::PushL( fieldArray );

    TPbkFieldLocation locs[] = { 
        EPbkFieldLocationNone, 
        EPbkFieldLocationHome,
        EPbkFieldLocationWork };

    TInt locCount = sizeof( locs ) / sizeof( TPbkFieldLocation );

    for ( TInt i = 0; i < locCount; i++ )
        {
        CPbkFieldInfo* field = fields.Find( aFieldInfo.FieldId(), locs[i] );
        if ( field != NULL )
            {
            fieldArray->AppendL( field );
            }
        }
    
    aFieldCount = fieldArray->Count();
    CPbkFieldInfo* retField = NULL;
    if ( fieldArray->Count() == 1 )
        {
        retField = ( *fieldArray )[0];
        }
    else
        {
        CPbkItemTypeSelectAddToExisting* selectionDlg = 
            new ( ELeave ) CPbkItemTypeSelectAddToExisting();
        retField = selectionDlg->ExecuteLD( *fieldArray );
        }
    CleanupStack::PopAndDestroy( fieldArray );
    return retField;
    }

