/*
* Copyright (c) 2002 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: 
*       Provides methods for Phonebook Single Item Fetch API.
*
*/


// INCLUDE FILES
#include "CPbkSingleItemFetchDlg.h"  // This class

#include <avkon.rsg>
#include <StringLoader.h>

#include <PbkView.rsg>
#include "CPbkFetchDlg.h"
#include "MPbkFetchCallbacks.h"
#include "CPbkSelectFieldDlg.h"

#include <CPbkContactEngine.h>
#include <CPbkContactItem.h>
#include <CPbkFieldInfo.h>

// Unnamed namespace for local definitions
namespace {

// LOCAL CONSTANTS AND MACROS
#ifdef _DEBUG
enum TPanicCode
    {
    EPanicPostCond_Constructor = 1,
    EPanicPreCond_ConstructL,
    EPanicPreCond_ExecuteLD
    };

void Panic(TPanicCode aReason)
    {
    _LIT(KPanicText, "CPbkSingleItemFetchDlg");
    User::Panic(KPanicText, aReason);
    }
#endif // _DEBUG

CPbkFieldArray* CreateFieldArrayLC
        (const CPbkContactItem& aItem, const CPbkFieldIdArray* aFieldIds)
    {
    CPbkFieldArray* fieldArray = new(ELeave) CPbkFieldArray;
    CleanupStack::PushL(fieldArray);
    const TInt count = aItem.CardFields().Count();
    for (TInt i=0; i < count; ++i)
        {
        const TPbkContactItemField& field = aItem.CardFields()[i];
        // Add only nonempty fields
        if (!field.IsEmptyOrAllSpaces())
            {
            if (!aFieldIds)
                {
                // add all nonempty fields if no field type filter is given
                fieldArray->AppendL(field);
                }
            else
                {
                // Check that field's type matches with selectable types
                if (aFieldIds->Contains(field.FieldInfo().FieldId()))
                    {
                    fieldArray->AppendL(field);
                    }
                }
            }
        }
    return fieldArray;
    }

}  // namespace


// MODULE DATA STRUCTURES

/**
 * MPbkFetchDlgAccept implementation for CPbkSingleItemFetchDlg.
 */
NONSHARABLE_CLASS(CPbkSingleItemFetchDlg::TFetchCallback) : 
        public MPbkFetchDlgAccept
    {
    public: // constructor
        inline TFetchCallback(CPbkSingleItemFetchDlg& aFetchDlg) 
            : iFetchDlg(aFetchDlg)
            {
            };

    public: // from MPbkFetchEntryDlgAccept
        /**
         * called by CPbkFetchEntryDlg when selection is made. 
         * @param aId   The focused contact entry
         * @param aMarkedEntries    The marked contact entries
         * @return          ETrue to close CPbkFetchEntryDlg, 
         *                  EFalse to keep open.
         */
        TPbkFetchAccepted PbkFetchAcceptedL
            (TContactItemId aId, CContactIdArray* aMarkedEntries);

    private:
        /// Ref: to parent
        CPbkSingleItemFetchDlg& iFetchDlg;
    };


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

// CPbkSingleItemFetchDlg::TFetchCallback
MPbkFetchDlgAccept::TPbkFetchAccepted CPbkSingleItemFetchDlg::TFetchCallback::PbkFetchAcceptedL
        (TContactItemId aId, CContactIdArray* /*aMarkedEntries*/)
    {
    if (iFetchDlg.EntryFetchAcceptedL(aId))
        {
        return KFetchYes;
        }
    return KFetchNo;
    }

// CPbkSingleItemFetchDlg::TParams
EXPORT_C CPbkSingleItemFetchDlg::TParams::TParams() :
    iContactView(NULL), 
    iFieldIdArray(NULL), 
    iContactItem(NULL),
    iContactItemField(NULL),
    iCbaId(0)
    {
    }

EXPORT_C CPbkSingleItemFetchDlg::TParams::operator TCleanupItem()
    {
    return TCleanupItem(Cleanup,this);
    }

void CPbkSingleItemFetchDlg::TParams::Cleanup(TAny* aSelf)
    {
    TParams* self = static_cast<TParams*>(aSelf);
    delete self->iContactItem;
    self->iContactItem = NULL;
    self->iContactItemField = NULL;
    }

// CPbkSingleItemFetchDlg
inline CPbkSingleItemFetchDlg::CPbkSingleItemFetchDlg
        (TParams& aParams, 
        CPbkContactEngine& aEngine) : 
    iParams(aParams),
    iContactView(aParams.iContactView),
    iPbkEngine(aEngine)
    {
    // PostCond
    __ASSERT_DEBUG(!iFetchDlg && !iDestroyedPtr, Panic(EPanicPostCond_Constructor));
    }

inline void CPbkSingleItemFetchDlg::ConstructL()
    {
    // PreCond
    __ASSERT_DEBUG(!iFetchDlg && !iDestroyedPtr, Panic(EPanicPreCond_ConstructL));

    // Set up contact array if needed
    if (!iContactView)
        {
        iContactView = &iPbkEngine.AllContactsView();
        }
    }

EXPORT_C CPbkSingleItemFetchDlg* CPbkSingleItemFetchDlg::NewL
        (TParams& aParams, CPbkContactEngine& aEngine)
    {
    CPbkSingleItemFetchDlg* self = new(ELeave) CPbkSingleItemFetchDlg(aParams, aEngine);
    CleanupStack::PushL(self);
    self->ConstructL();
    CleanupStack::Pop();  // self
    return self;
    }

EXPORT_C void CPbkSingleItemFetchDlg::SetMopParent(MObjectProvider* aParent)
    {
    iObjectProvider = aParent;
    }

EXPORT_C TInt CPbkSingleItemFetchDlg::ExecuteLD()
    {
    // PreCond
    __ASSERT_DEBUG(iContactView, Panic(EPanicPreCond_ExecuteLD));

    // "D" function semantics
    CleanupStack::PushL(this);
    TBool thisDestroyed = EFalse;
    // Destructor sets thisDestroyed to ETrue
    iDestroyedPtr = &thisDestroyed;

    // Convert aParams for CPbkFetchDlg
    CPbkFetchDlg::TParams params;
    params.iResId = R_PBK_SINGLE_ENTRY_FETCH_DLG;
    params.iFlags = CPbkFetchDlg::FETCH_FOCUSED;
    params.iContactView = iContactView;
    params.iMarkedEntries = NULL;
    TFetchCallback callback(*this);
    params.iAcceptCallback = &callback;
    params.iCbaId = iParams.iCbaId;

    iFetchDlg = CPbkFetchDlg::NewL(params, iPbkEngine);
    iFetchDlg->ResetWhenDestroyed(&iFetchDlg);
    iFetchDlg->SetMopParent(iObjectProvider);
    TInt result = iFetchDlg->ExecuteLD();
    
    if (thisDestroyed)
        {
        // this object was destroyed
        result = 0;
        CleanupStack::Pop(this);
        }
    else
        {
        if (result)
            {
            // Switch ownership of result objects to iParams
            iParams.iContactItem = iContactItem;
            iContactItem = NULL;
            iParams.iContactItemField = iContactItemField;
            iContactItemField = NULL;
            }
        CleanupStack::PopAndDestroy(this);
        }

    return result;
    }

TBool CPbkSingleItemFetchDlg::EntryFetchAcceptedL
        (TContactItemId aCid)
    {
    TBool thisDestroyed = EFalse;
    TBool* prevDestroyedPtr = iDestroyedPtr;
    iDestroyedPtr = &thisDestroyed;

    CPbkContactItem* item = iPbkEngine.ReadContactLC(aCid);

    // create array of fields    
    CPbkFieldArray* fieldArray = 
        CreateFieldArrayLC(*item, iParams.iFieldIdArray);

    TPbkContactItemField* field = NULL;

    if ( fieldArray->Count() != 1 )
        {
        HBufC* heading = StringLoader::LoadLC(R_QTN_PHOB_QTL_SELECT_ONE_ITEM);

        iFieldDlg = new(ELeave) CPbkSelectFieldDlg;
        iFieldDlg->ResetWhenDestroyed(&iFieldDlg);
        TInt cbaResourceId( R_AVKON_SOFTKEYS_SELECT_CANCEL__SELECT );
        if ( fieldArray->Count() == 0 )
            {
            // If field selection is empty, only back soft button
            // is available
            cbaResourceId = R_AVKON_SOFTKEYS_BACK;
            }
        field = iFieldDlg->ExecuteLD(*fieldArray, 
                cbaResourceId, *heading);
        CleanupStack::PopAndDestroy(heading);
        }
    else
        {
        // Only one field in the array, grab it!
        field = &fieldArray->At(0);
        }
    
    if (thisDestroyed)
        {
        // This must be enough to ensure that rest of the code in this 
        // function doesn't access member variables, this object has been 
        // destroyed, remember!
        if (prevDestroyedPtr) *prevDestroyedPtr = ETrue;
        field = NULL;
        }
    else
        {
        iDestroyedPtr = prevDestroyedPtr;
        }

    if (field)
        {
        const TInt index = item->FindFieldIndex(*field);
        TPbkContactItemField& itemField = item->CardFields()[index];
        CleanupStack::PopAndDestroy(fieldArray);
        CleanupStack::Pop(item);
        // Take ownership of item
        iContactItem = item;
        iContactItemField = &itemField;
        }
    else
        {
        CleanupStack::PopAndDestroy(2,item);
        }

    return (field!=NULL); 
    }

CPbkSingleItemFetchDlg::~CPbkSingleItemFetchDlg()
    {
    if (iDestroyedPtr) 
        {
        *iDestroyedPtr = ETrue;
        }

    // Close the dialogs
    delete iFieldDlg;
    delete iFetchDlg;

    // delete return values in case of cancel
    delete iContactItem;
    }


//  End of File  
