phonebookui/Phonebook/Engine/src/CPbkContactItemOld.cpp
changeset 0 e686773b3f54
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/phonebookui/Phonebook/Engine/src/CPbkContactItemOld.cpp	Tue Feb 02 10:12:17 2010 +0200
@@ -0,0 +1,1600 @@
+/*
+* 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: 
+*		Phonebook Contact item class
+*
+*/
+
+
+// INCLUDE FILES
+#include    "CPbkContactItem.h"
+#include    <cntfield.h>    // CContactItemField
+#include    <cntitem.h>     // CContactItem
+#include    <FeatMgr.h>	    // Feature manager
+#include    <CPbkSINDHandlerInterface.h>
+#include    "CPbkFieldsInfo.h"
+#include    "CPbkFieldInfo.h"
+#include    "TPbkContactItemField.h"
+#include    "PbkFields.hrh"
+#include    <PbkEngUtils.h>
+#include    <pbkdebug.h>
+#include    "PbkDefaults.h"
+#include    <MPbkContactNameFormat.h>
+#include    "TPbkMatchPriorityLevel.h"
+#include    "CPbkContactEngine.h"
+#include    "cpbkenginelocalstorage.h"
+#include    "CPbkSyncronizationConstants.h"
+
+#ifdef _DEBUG
+// Engine needed only for a few asserts
+#include    "CPbkContactEngine.h"
+#endif
+
+// Unnamed namespace for local definitions
+
+namespace {
+
+// LOCAL CONSTANTS AND MACROS
+enum TPanicCode
+    {
+    EPanicPostCond_Constructor = 1,
+    EPanicPreCond_ConstructL,
+    EPanicInvariant_Pointer,
+    EPanicInvariant_Count,
+    EPanicInvariant_Field,
+    EPanicInvariant_FieldInfo,
+    EPanicInvariant_Sorting,
+    EPanicInvariant_PrefCount,
+    EPanicInvariant_SmsCount,
+    EPanicInvariant_PrefSmsCount,
+    EPanicInvariant_PhoneDefaultCount,
+    EPanicInvariant_SmsDefaultCount,
+    EPanicInvariant_EmailDefaultCount,
+    EPanicInvariant_VideoTagCount,
+    EPanicPostCond_FindFieldIndex,
+    EPanicPreCond_RemoveField,
+    EPanicLogic_RemoveField,
+    EPanicPostCond_RemoveField,
+    EPanicPostCond_AddFieldL,
+    EPanicPreCond_GroupsJoinedLC,
+    EPanicPostCond_SetDefaultPhoneNumberFieldL,
+    EPanicPostCond_SetDefaultVideoNumberFieldL,
+    EPanicPostCond_SetDefaultEmailFieldL,
+    EPanicPreCond_UpdateFieldSetL,
+    EPanicPostCond_InsertionPos,
+    EPanicPostCond_SetVoiceTagFieldL,
+    EPanicInvariant_VoiceTagCount,
+    EPanicInvariant_VoiceTagFieldCount,
+    EPanicPostCond_SetDefaultMmsFieldL,
+    EPanicPostCond_SetDefaultEmailOverSmsFieldL,
+    EPanicPostCond_SetDefaultPocFieldL,
+    EPanicPostCond_SetDefaultVoipFieldL,
+    EPanicPreCond_VoiceTagField1,
+    EPanicPreCond_VoiceTagField2,
+    EPanicPreCond_LoadSindHandlerImplL
+    };
+
+// ==================== LOCAL FUNCTIONS ====================
+
+void Panic(TPanicCode aReason)
+    {
+    _LIT(KPanicText, "CPbkContactItem");
+    User::Panic(KPanicText, aReason);
+    }
+
+/**
+ * Searches a field set for the first field with type specified type.
+ *
+ * @param aFields   the field set to search.
+ * @param aFieldInfo    the field type to search for.
+ * @param aIndex        index where to start the search.
+ * @return index of the matching field in aFields or KErrNotFound if not found.
+ */
+TInt FindFieldWithType
+        (const CPbkFieldArray& aFields,
+        const CPbkFieldInfo& aFieldInfo,
+        TInt aIndex=0)
+    {
+    const TInt fieldCount = aFields.Count();
+    for (TInt i=aIndex; i < fieldCount; ++i)
+        {
+        if (aFields[i].FieldInfo().IsSame(aFieldInfo))
+            {
+            return i;
+            }
+        }
+    return KErrNotFound;
+    }
+
+inline void LoadSindHandlerImplL(TUid& aDtorIDKey,
+    CPbkSINDHandlerInterface*& aSINDHandler)
+    {
+    // Check does the SIND handler implementation exist:
+    TUid interfaceUid = {KPbkSINDHandlerInterfaceUID};
+    RImplInfoPtrArray pluginArray;
+    REComSession::ListImplementationsL( interfaceUid ,pluginArray );
+    __ASSERT_DEBUG(pluginArray.Count() == 1, Panic(EPanicPreCond_LoadSindHandlerImplL));
+    if ( pluginArray.Count() > 0 )
+        {
+        // There should be only one implementation for SIND handler and
+        // we would like to use that one
+        TUid SINDHandlerImpUid = {KPbkSINDHandlerPluginUID};
+
+        aSINDHandler = static_cast<CPbkSINDHandlerInterface*>
+            (REComSession::CreateImplementationL(SINDHandlerImpUid ,aDtorIDKey));
+        }
+    pluginArray.ResetAndDestroy();
+    }
+
+}  // namespace
+
+
+// ================= MEMBER FUNCTIONS =======================
+
+/**
+ * C++ constructor.
+ */
+inline CPbkContactItem::CPbkContactItem(MPbkContactNameFormat& aNameFormat) :
+    iNameFormat(aNameFormat)
+    {
+    // new(ELeave) in NewL will reset members
+    __ASSERT_DEBUG(!iItem, Panic(EPanicPostCond_Constructor));
+    }
+
+/**
+ * Second phase constructor.
+ */
+inline void CPbkContactItem::ConstructL
+        (CContactItem* aItem,
+        const CPbkFieldsInfo& aFieldsInfo)
+    {
+    //PreCond:
+    __ASSERT_DEBUG(aItem && !iItem, Panic(EPanicPreCond_ConstructL));
+
+    CreateFieldArrayL(*aItem, aFieldsInfo);
+    // construction was succesful, take ownership of aItem
+    iItem = aItem;
+
+    // Philosophical note: class invariant is effectively a postcondition
+    // for a constructor.
+    __TEST_INVARIANT;
+    }
+
+EXPORT_C CPbkContactItem* CPbkContactItem::NewL
+        (CContactItem* aItem,
+        const CPbkFieldsInfo& aFieldsInfo,
+        MPbkContactNameFormat& aNameFormat)
+    {
+    CPbkContactItem* self = new(ELeave) CPbkContactItem(aNameFormat);
+    CleanupStack::PushL(self);
+    self->ConstructL(aItem, aFieldsInfo);
+    CleanupStack::Pop(self);
+    return self;
+    }
+
+CPbkContactItem::~CPbkContactItem()
+    {
+#ifdef _DEBUG
+    // Test invariant only at the beginning of destructor and only if
+    // construction was succesful.
+    if (iItem)
+        __TEST_INVARIANT;
+#endif
+
+    // Delete own data
+    delete iItem;
+    }
+
+EXPORT_C CContactItem& CPbkContactItem::ContactItem()
+    {
+    return *iItem;
+    }
+
+EXPORT_C const CContactItem& CPbkContactItem::ContactItem() const
+    {
+    return *iItem;
+    }
+
+EXPORT_C HBufC* CPbkContactItem::GetContactTitleL() const
+    {
+    __TEST_INVARIANT;
+
+    // Delegate call to iNameFormat
+    return iNameFormat.GetContactTitleL(*this);
+    }
+
+EXPORT_C HBufC* CPbkContactItem::GetContactTitleOrNullL() const
+    {
+    __TEST_INVARIANT;
+
+    // Delegate call to iNameFormat
+    return iNameFormat.GetContactTitleOrNullL(*this);
+    }
+
+EXPORT_C TPbkIconId CPbkContactItem::ContactIconIdL() const
+    {
+    __TEST_INVARIANT;
+
+    TPbkContactItemField* field = DefaultPhoneNumberField();
+    if (field)
+        {
+        return field->IconId();
+        }
+    return EPbkNullIconId;
+    }
+
+EXPORT_C TPbkContactItemField* CPbkContactItem::DefaultPhoneNumberField() const
+    {
+    PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+
+    // scan the fields for a match in default field for field id.
+    const TInt fieldCount = iFields.Count();
+    for(TInt i=0; i < fieldCount; ++i)
+        {
+        if (iFields[i].DefaultPhoneNumberField())
+            {
+            return const_cast<TPbkContactItemField*>(&(iFields[i]));
+            }
+        }
+    return NULL;
+    }
+
+EXPORT_C void CPbkContactItem::SetDefaultPhoneNumberFieldL
+        (TPbkContactItemField* aField)
+    {
+    PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+
+    if (aField)
+        {
+        aField = FindSameField(*aField);
+        if (!aField)
+            {
+            // Not this item's field
+            User::Leave(KErrNotFound);
+            }
+        }
+
+    // Test can we set the default for this field
+    if (aField && !aField->FieldInfo().IsPhoneNumberField())
+        {
+        User::Leave(KErrNotSupported);
+        }
+
+    // 1. Fetch previous default
+    TPbkContactItemField* prevDefault = DefaultPhoneNumberField();
+
+    // 2. Set the new default, if specified
+    if (aField)
+        {
+        if (prevDefault == aField)
+            {
+            // Default already set to aField
+            return;
+            }
+        // If this leaves, this object's state remains unchanged
+        aField->ItemField().AddFieldTypeL(KUidPbkDefaultFieldPref);
+        }
+
+    // 3. Unset any previous default (invariant tests that there is always just
+    // one default.
+    if (prevDefault)
+        {
+        // Unset previous default
+        prevDefault->ItemField().RemoveFieldType(KUidPbkDefaultFieldPref);
+        }
+
+    __ASSERT_DEBUG(
+        (aField && DefaultPhoneNumberField()==aField) ||
+        (!aField && !DefaultPhoneNumberField()),
+        Panic(EPanicPostCond_SetDefaultPhoneNumberFieldL));
+    }
+
+EXPORT_C void CPbkContactItem::RemoveDefaultPhoneNumberField()
+    {
+    // This is safe because SetDefaultPhoneNumberFieldL(NULL)
+    // guarantees not to leave
+    SetDefaultPhoneNumberFieldL(NULL);
+    }
+
+EXPORT_C TPbkContactItemField* CPbkContactItem::DefaultVideoNumberField() const
+    {
+    PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+
+    // scan the fields for a match in default field for field id.
+    const TInt fieldCount = iFields.Count();
+    for(TInt i=0; i < fieldCount; ++i)
+        {
+        if (iFields[i].DefaultVideoNumberField())
+            {
+            return const_cast<TPbkContactItemField*>(&(iFields[i]));
+            }
+        }
+    return NULL;
+    }
+
+EXPORT_C void CPbkContactItem::SetDefaultVideoNumberFieldL
+        (TPbkContactItemField* aField)
+    {
+    PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+
+    if (aField)
+        {
+        aField = FindSameField(*aField);
+        if (!aField)
+            {
+            // Not this item's field
+            User::Leave(KErrNotFound);
+            }
+        }
+
+    // Test can we set the default for this field
+    if (aField && !aField->FieldInfo().IsPhoneNumberField())
+        {
+        User::Leave(KErrNotSupported);
+        }
+
+    // 1. Fetch previous default
+    TPbkContactItemField* prevDefault = DefaultVideoNumberField();
+
+    // 2. Set the new default, if specified
+    if (aField)
+        {
+        if (prevDefault == aField)
+            {
+            // Default already set to aField
+            return;
+            }
+        // If this leaves, this object's state remains unchanged
+        aField->ItemField().AddFieldTypeL(KUidPbkDefaultFieldVideo);
+        }
+
+    // 3. Unset any previous default (invariant tests that there is always just
+    // one default.
+    if (prevDefault)
+        {
+        // Unset previous default
+        prevDefault->ItemField().RemoveFieldType(KUidPbkDefaultFieldVideo);
+        }
+
+    __ASSERT_DEBUG(
+        (aField && DefaultVideoNumberField()==aField) ||
+        (!aField && !DefaultVideoNumberField()),
+        Panic(EPanicPostCond_SetDefaultVideoNumberFieldL));
+    }
+
+EXPORT_C void CPbkContactItem::RemoveDefaultVideoNumberField()
+    {
+    // This is safe because SetDefaultPhoneNumberFieldL(NULL)
+    // guarantees not to leave
+    SetDefaultVideoNumberFieldL(NULL);
+    }
+
+EXPORT_C TPbkContactItemField* CPbkContactItem::DefaultSmsField() const
+    {
+    PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+
+    const TInt fieldCount = iFields.Count();
+    for (TInt i=0; i < fieldCount; ++i)
+        {
+        const TPbkContactItemField& field = iFields[i];
+        if (field.DefaultSmsField())
+            {
+            return const_cast<TPbkContactItemField*>(&field);
+            }
+        }
+    return NULL;
+    }
+
+EXPORT_C void CPbkContactItem::SetDefaultSmsFieldL
+        (TPbkContactItemField* aField)
+    {
+    PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+
+    if (aField)
+        {
+        aField = FindSameField(*aField);
+        if (!aField)
+            {
+            // Not this item's field
+            User::Leave(KErrNotFound);
+            }
+        }
+
+    // Test can we set the default for this field
+    if (aField && !aField->FieldInfo().IsPhoneNumberField())
+        {
+        User::Leave(KErrNotSupported);
+        }
+
+    // 1. Fetch previous default
+    TPbkContactItemField* prevDefault = DefaultSmsField();
+
+    // 2. Set the new default if specified
+    if (aField)
+        {
+        if (aField == prevDefault)
+            {
+            // Already set
+            return;
+            }
+        // If this leaves, this object's state remains unchanged
+        aField->ItemField().AddFieldTypeL(KUidPbkDefaultFieldSms);
+        }
+
+    // 3. Unset any previous default (invariant tests that there is always just
+    // one default).
+    if (prevDefault)
+        {
+        prevDefault->ItemField().RemoveFieldType(KUidPbkDefaultFieldSms);
+        }
+
+    __ASSERT_DEBUG(
+        (aField && DefaultSmsField()==aField) ||
+        (!aField && !DefaultSmsField()),
+        Panic(EPanicPostCond_SetDefaultPhoneNumberFieldL));
+    }
+
+EXPORT_C void CPbkContactItem::RemoveDefaultSmsField()
+    {
+    // This is safe because SetDefaultSmsFieldL(NULL) guarantees
+    // not to leave
+    SetDefaultSmsFieldL(NULL);
+    }
+
+EXPORT_C TPbkContactItemField* CPbkContactItem::DefaultEmailField() const
+    {
+    PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+
+    // scan the fields for a match in default field for field id.
+    const TInt fieldCount = iFields.Count();
+    for (TInt i = 0; i < fieldCount; ++i)
+        {
+        const TPbkContactItemField& field = iFields[i];
+        if (field.DefaultEmailField())
+            {
+            return const_cast<TPbkContactItemField*>(&field);
+            }
+        }
+    return NULL;
+    }
+
+EXPORT_C void CPbkContactItem::SetDefaultEmailFieldL
+        (TPbkContactItemField* aField)
+    {
+    PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+
+    if (aField)
+        {
+        aField = FindSameField(*aField);
+        if (!aField)
+            {
+            // Not this item's field
+            User::Leave(KErrNotFound);
+            }
+        }
+
+    if (aField && aField->FieldInfo().FieldId() != EPbkFieldIdEmailAddress)
+        {
+        User::Leave(KErrNotSupported);
+        }
+
+    // 1. Fetch previous default
+    TPbkContactItemField* prevDefault = DefaultEmailField();
+
+    // 2. Set the new default if specified
+    if (aField)
+        {
+        if (aField == prevDefault)
+            {
+            // Already set
+            return;
+            }
+        aField->ItemField().AddFieldTypeL(KUidPbkDefaultFieldPref);
+        }
+
+    // 3. Unset any previous default (invariant tests that there is always just
+    // one default).
+    if (prevDefault)
+        {
+        prevDefault->ItemField().RemoveFieldType(KUidPbkDefaultFieldPref);
+        }
+
+    __ASSERT_DEBUG(
+        (aField && DefaultEmailField()==aField) ||
+        (!aField && !DefaultEmailField()),
+        Panic(EPanicPostCond_SetDefaultEmailFieldL));
+    }
+
+EXPORT_C void CPbkContactItem::RemoveDefaultEmailField()
+    {
+    // This is safe because SetDefaultEmailFieldL(NULL) guarantees
+    // not to leave
+    SetDefaultEmailFieldL(NULL);
+    }
+
+
+EXPORT_C TPbkContactItemField* CPbkContactItem::DefaultEmailOverSmsField() const
+    {
+    PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+
+    // scan the fields for a match in default field for field id.
+    const TInt fieldCount = iFields.Count();
+    for (TInt i = 0; i < fieldCount; ++i)
+        {
+        const TPbkContactItemField& field = iFields[i];
+        if (field.DefaultEmailOverSmsField())
+            {
+            return const_cast<TPbkContactItemField*>(&field);
+            }
+        }
+    return NULL;
+    }
+
+EXPORT_C void CPbkContactItem::SetDefaultEmailOverSmsFieldL
+        (TPbkContactItemField* aField)
+    {
+    PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+
+    if (aField)
+        {
+        aField = FindSameField(*aField);
+        if (!aField)
+            {
+            // Not this item's field
+            User::Leave(KErrNotFound);
+            }
+        }
+
+    if (aField && !aField->FieldInfo().IsEmailOverSmsField())
+        {
+        User::Leave(KErrNotSupported);
+        }
+
+    // 1. Fetch previous default
+    TPbkContactItemField* prevDefault = DefaultEmailOverSmsField();
+
+    // 2. Set the new default if specified
+    if (aField)
+        {
+        if (aField == prevDefault)
+            {
+            // Already set
+            return;
+            }
+        aField->ItemField().AddFieldTypeL(KUidPbkDefaultFieldEmailOverSms);
+        }
+
+    // 3. Unset any previous default (invariant tests that there is always just
+    // one default).
+    if (prevDefault)
+        {
+        prevDefault->ItemField().RemoveFieldType(KUidPbkDefaultFieldEmailOverSms);
+        }
+
+    __ASSERT_DEBUG(
+        (aField && DefaultEmailOverSmsField()==aField) ||
+        (!aField && !DefaultEmailOverSmsField()),
+        Panic(EPanicPostCond_SetDefaultEmailOverSmsFieldL));
+    }
+
+EXPORT_C void CPbkContactItem::RemoveDefaultEmailOverSmsField()
+    {
+    // This is safe because SetDefaultEmailOverSmsFieldL(NULL) guarantees
+    // not to leave
+    SetDefaultEmailOverSmsFieldL(NULL);
+    }
+
+EXPORT_C TPbkContactItemField* CPbkContactItem::DefaultMmsField() const
+    {
+    PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+
+    // scan the fields for a match in default field for field id.
+    const TInt fieldCount = iFields.Count();
+    for (TInt i = 0; i < fieldCount; ++i)
+        {
+        const TPbkContactItemField& field = iFields[i];
+        if (field.DefaultMmsField())
+            {
+            return const_cast<TPbkContactItemField*>(&field);
+            }
+        }
+    return NULL;
+    }
+
+EXPORT_C void CPbkContactItem::SetDefaultMmsFieldL
+        (TPbkContactItemField* aField)
+    {
+    PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+
+    if (aField)
+        {
+        aField = FindSameField(*aField);
+        if (!aField)
+            {
+            // Not this item's field
+            User::Leave(KErrNotFound);
+            }
+        }
+
+    if (aField && !aField->FieldInfo().IsMmsField())
+        {
+        User::Leave(KErrNotSupported);
+        }
+
+    // 1. Fetch previous default
+    TPbkContactItemField* prevDefault = DefaultMmsField();
+
+    // 2. Set the new default if specified
+    if (aField)
+        {
+        if (aField == prevDefault)
+            {
+            // Already set
+            return;
+            }
+        aField->ItemField().AddFieldTypeL(KUidPbkDefaultFieldMms);
+        }
+
+    // 3. Unset any previous default (invariant tests that there is always just
+    // one default).
+    if (prevDefault)
+        {
+        prevDefault->ItemField().RemoveFieldType(KUidPbkDefaultFieldMms);
+        }
+
+    __ASSERT_DEBUG(
+        (aField && DefaultMmsField()==aField) ||
+        (!aField && !DefaultMmsField()),
+        Panic(EPanicPostCond_SetDefaultMmsFieldL));
+    }
+
+EXPORT_C void CPbkContactItem::RemoveDefaultMmsField()
+    {
+    // This is safe because SetDefaultMmsFieldL(NULL) guarantees
+    // not to leave
+    SetDefaultMmsFieldL(NULL);
+    }
+
+EXPORT_C TPbkContactItemField* CPbkContactItem::DefaultPocField() const
+    {
+    PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+
+    // scan the fields for a match in default field for field id.
+    const TInt fieldCount = iFields.Count();
+    for (TInt i = 0; i < fieldCount; ++i)
+        {
+        const TPbkContactItemField& field = iFields[i];
+        if (field.DefaultPocField())
+            {
+            return const_cast<TPbkContactItemField*>(&field);
+            }
+        }
+    return NULL;
+    }
+
+EXPORT_C void CPbkContactItem::SetDefaultPocFieldL
+        (TPbkContactItemField* aField)
+    {
+    PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+
+    if (aField)
+        {
+        aField = FindSameField(*aField);
+        if (!aField)
+            {
+            // Not this item's field
+            User::Leave(KErrNotFound);
+            }
+        }
+
+    if (aField && !aField->FieldInfo().IsPocField())
+        {
+        User::Leave(KErrNotSupported);
+        }
+
+    // 1. Fetch previous default
+    TPbkContactItemField* prevDefault = DefaultPocField();
+
+    // 2. Set the new default if specified
+    if (aField)
+        {
+        if (aField == prevDefault)
+            {
+            // Already set
+            return;
+            }
+        aField->ItemField().AddFieldTypeL(KUidPbkDefaultFieldPoc);
+        }
+
+    // 3. Unset any previous default (invariant tests that there is always just
+    // one default).
+    if (prevDefault)
+        {
+        prevDefault->ItemField().RemoveFieldType(KUidPbkDefaultFieldPoc);
+        }
+
+    __ASSERT_DEBUG(
+        (aField && DefaultPocField()==aField) ||
+        (!aField && !DefaultPocField()),
+        Panic(EPanicPostCond_SetDefaultPocFieldL));
+    }
+
+EXPORT_C void CPbkContactItem::RemoveDefaultPocField()
+    {
+    // This is safe because SetDefaultPocFieldL(NULL) guarantees
+    // not to leave
+    SetDefaultPocFieldL(NULL);
+    }
+
+EXPORT_C TPbkContactItemField* CPbkContactItem::DefaultVoipField() const
+    {
+    PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+
+    // scan the fields for a match in default field for field id.
+    const TInt fieldCount = iFields.Count();
+    for (TInt i = 0; i < fieldCount; ++i)
+        {
+        const TPbkContactItemField& field = iFields[i];
+        if (field.DefaultVoipField())
+            {
+            return const_cast<TPbkContactItemField*>(&field);
+            }
+        }
+    return NULL;
+    }
+
+EXPORT_C void CPbkContactItem::SetDefaultVoipFieldL
+        (TPbkContactItemField* aField)
+    {
+    PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+
+    if (aField)
+        {
+        aField = FindSameField(*aField);
+        if (!aField)
+            {
+            // Not this item's field
+            User::Leave(KErrNotFound);
+            }
+        }
+
+    if (aField && !aField->FieldInfo().IsVoipField())
+        {
+        User::Leave(KErrNotSupported);
+        }
+
+    // 1. Fetch previous default
+    TPbkContactItemField* prevDefault = DefaultVoipField();
+
+    // 2. Set the new default if specified
+    if (aField)
+        {
+        if (aField == prevDefault)
+            {
+            // Already set
+            return;
+            }
+        aField->ItemField().AddFieldTypeL(KUidPbkDefaultFieldVoip);
+        }
+
+    // 3. Unset any previous default (invariant tests that there is always just
+    // one default).
+    if (prevDefault)
+        {
+        prevDefault->ItemField().RemoveFieldType(KUidPbkDefaultFieldVoip);
+        }
+
+    __ASSERT_DEBUG(
+        (aField && DefaultVoipField()==aField) ||
+        (!aField && !DefaultVoipField()),
+        Panic(EPanicPostCond_SetDefaultVoipFieldL));
+    }
+
+EXPORT_C void CPbkContactItem::RemoveDefaultVoipField()
+    {
+    // This is safe because SetDefaultVoipFieldL(NULL) guarantees
+    // not to leave
+    SetDefaultVoipFieldL(NULL);
+    }
+
+EXPORT_C TPbkContactItemField* CPbkContactItem::VoiceTagField() const
+    {
+    TPbkContactItemField* ret = NULL;
+
+    if (FeatureManager::FeatureSupported( KFeatureIdSind ))
+        {
+        // Try to initiaze SindHandler.
+        CPbkEngineLocalStorage* storage =
+            reinterpret_cast<CPbkEngineLocalStorage*> ( Dll::Tls( ) );
+
+        if (storage && !storage->iSINDHandler)
+            {
+            // SindHandler lazy construction.
+            // Possible leave codes ignored.
+            TRAP_IGNORE(LoadSindHandlerImplL(storage->iDtorIDKey,
+                storage->iSINDHandler));
+            if (storage->iSINDHandler)
+                {
+                // Update engine TLS if SindHandler is loaded
+                TInt err = Dll::SetTls(storage);
+                __ASSERT_DEBUG( err == KErrNone,
+                    Panic( EPanicPreCond_VoiceTagField2 ) );
+                }
+            }
+
+        if ( storage && storage->iSINDHandler )
+            {
+            TPbkFieldId voiceTaggedFieldId =
+                storage->iSINDHandler->VoiceTagField(Id());
+
+            if ( voiceTaggedFieldId >= 0 ) // otherwise error has occured
+                {
+				// check is default call number set
+				TPbkContactItemField* defaultField = DefaultPhoneNumberField();
+				if ( defaultField )
+					{
+					return defaultField;
+					}
+                const TInt fieldCount = iFields.Count();
+                for (TInt i = 0; i < fieldCount; ++i)
+                    {
+                    const TPbkContactItemField& field = iFields[i];
+                    if ( field.PbkFieldId() == voiceTaggedFieldId )
+                        {
+                        ret = const_cast<TPbkContactItemField*>(&field);
+                        break;
+                        }
+                    }
+                }
+            }
+
+        // If the field id does not match with existing fields or the
+        // sindhandler return error (not found), NULL is returned.
+        }
+    else
+        {
+        // scan the fields for a match in voice tag field for field id.
+        const TInt fieldCount = iFields.Count();
+        for (TInt i = 0; i < fieldCount; ++i)
+            {
+            const TPbkContactItemField& field = iFields[i];
+            if (field.ItemField().ContentType().ContainsFieldType(
+                KUidContactsVoiceDialField))
+                {
+                ret = const_cast<TPbkContactItemField*>(&field);
+                break;
+                }
+            }
+        }
+
+    return ret;
+    }
+
+EXPORT_C void CPbkContactItem::SetVoiceTagFieldL
+        (TPbkContactItemField* aField)
+    {
+    PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+    if ( !FeatureManager::FeatureSupported(KFeatureIdSind) )
+        {
+
+        if (aField)
+            {
+            aField = FindSameField(*aField);
+            if (!aField)
+                {
+                // Not this item's field
+                User::Leave(KErrNotFound);
+                }
+            }
+
+        // Test can we set a voice tag for this field
+        // The VoIP field completely includes the IsPhoneNumberField subset,
+        // so its enough to test with IsVoipField method only.
+        if (aField && !aField->FieldInfo().IsVoipField())
+            {
+            User::Leave(KErrNotSupported);
+            }
+
+        // 1. Fetch previous voice tag field
+        TPbkContactItemField* prevTag = VoiceTagField();
+
+        // 2. Set the new voice tag, if specified
+        if (aField)
+            {
+            if (prevTag == aField)
+                {
+                // Voice tag already set to aField
+                return;
+                }
+            // If this leaves, this object's state remains unchanged
+            aField->ItemField().AddFieldTypeL(KUidContactsVoiceDialField);
+            }
+
+        // 3. Unset any previous voice tag (invariant tests that there is always
+        // just one voice tag).
+        if (prevTag)
+            {
+            // Unset previous voice tag
+            prevTag->ItemField().RemoveFieldType(KUidContactsVoiceDialField);
+            }
+
+        __ASSERT_DEBUG(
+            (aField && VoiceTagField()==aField) ||
+            (!aField && !VoiceTagField()),
+            Panic(EPanicPostCond_SetVoiceTagFieldL));
+        }
+    }
+
+EXPORT_C void CPbkContactItem::RemoveVoiceTagField()
+    {
+    if ( !FeatureManager::FeatureSupported(KFeatureIdSind) )
+        {
+        // This is safe because SetVoiceTagFieldL(NULL) guarantees
+        // not to leave
+        SetVoiceTagFieldL(NULL);
+        }
+    }
+
+EXPORT_C TPbkContactItemField* CPbkContactItem::FindField
+        (TPbkFieldId aFieldId) const
+    {
+    TInt index = 0;
+    return FindField(aFieldId, index);
+    }
+
+EXPORT_C TPbkContactItemField* CPbkContactItem::FindField
+        (TPbkFieldId aFieldId, TInt& aIndex) const
+    {
+    __TEST_INVARIANT;
+
+    const TInt fieldCount = iFields.Count();
+    for (TInt i = Max(aIndex,0) ; i < fieldCount; ++i)
+        {
+        const TPbkContactItemField& field = iFields[i];
+        if (field.FieldInfo().Match(aFieldId))
+            {
+            aIndex = i;
+            return const_cast<TPbkContactItemField*>(&field);
+            }
+        }
+
+    aIndex = KErrNotFound;
+    return NULL;
+    }
+
+EXPORT_C TPbkContactItemField* CPbkContactItem::FindField
+        (const CPbkFieldInfo& aFieldInfo) const
+    {
+    TInt index = 0;
+    return FindField(aFieldInfo, index);
+    }
+
+EXPORT_C TPbkContactItemField* CPbkContactItem::FindField
+        (const CPbkFieldInfo& aFieldInfo, TInt& aIndex) const
+    {
+    __TEST_INVARIANT;
+
+    aIndex = FindFieldWithType(iFields, aFieldInfo, Max(aIndex,0));
+    if (aIndex != KErrNotFound)
+        {
+        return const_cast<TPbkContactItemField*>(&iFields[aIndex]);
+        }
+    else
+        {
+        return NULL;
+        }
+    }
+
+EXPORT_C TInt CPbkContactItem::FindFieldIndex
+        (const TPbkContactItemField& aField) const
+    {
+    PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+
+    const TInt fieldCount = iFields.Count();
+    for (TInt i = 0; i < fieldCount; ++i)
+        {
+        if(iFields[i].IsSame(aField))
+            {
+            __ASSERT_DEBUG(CardFields()[i].IsSame(aField),
+                Panic(EPanicPostCond_FindFieldIndex));
+            return i;
+            }
+        }
+
+    return KErrNotFound;
+    }
+
+EXPORT_C TInt CPbkContactItem::FindContactItemFieldIndex
+        (const CContactItemField& aField) const
+    {
+    PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+
+    const CContactItemFieldSet& fields = iItem->CardFields();
+    const TInt fieldCount = fields.Count();
+    for (TInt i = 0; i < fieldCount; ++i)
+        {
+        if (&fields[i] == &aField)
+            {
+            return i;
+            }
+        }
+    return KErrNotFound;
+    }
+
+EXPORT_C TPbkContactItemField* CPbkContactItem::FindNextFieldWithPhoneNumber(
+        const TDesC& aNumber,
+        TInt aNumberOfDigits,
+        TInt& aIndex) const
+    {
+    __TEST_INVARIANT;
+
+    const TInt fieldCount = iFields.Count();
+    for (TInt i = Max(aIndex,0); i < fieldCount; ++i)
+        {
+        const TPbkContactItemField& field = iFields[i];
+        if (field.FieldInfo().IsPhoneNumberField())
+            {
+            if (PbkEngUtils::ContainSameDigits(field.Text(), aNumber,
+                aNumberOfDigits))
+                {
+                aIndex = i;
+                return const_cast<TPbkContactItemField*>(&field);
+                }
+            }
+        }
+
+    aIndex = KErrNotFound;
+    return NULL;
+    }
+
+EXPORT_C TPbkContactItemField* CPbkContactItem::FindNextFieldWithText
+        (const TDesC& aText,
+        TInt& aIndex) const
+    {
+    __TEST_INVARIANT;
+
+    const TInt fieldCount = iFields.Count();
+    for (TInt i = Max(aIndex,0); i < fieldCount; ++i)
+        {
+        const TPbkContactItemField& field = iFields[i];
+        if (field.StorageType() == KStorageTypeText)
+            {
+            if (field.Text().FindF(aText) >= 0)
+                {
+                aIndex = i;
+                return const_cast<TPbkContactItemField*>(&field);
+                }
+            }
+        }
+
+    aIndex = KErrNotFound;
+    return NULL;
+    }
+
+EXPORT_C TPbkContactItemField* CPbkContactItem::FindSameField
+        (const TPbkContactItemField& aField) const
+    {
+    const TInt fieldCount = iFields.Count();
+    for (TInt i=0; i < fieldCount; ++i)
+        {
+        if (iFields[i].IsSame(aField))
+            {
+            return const_cast<TPbkContactItemField*>(&iFields[i]);
+            }
+        }
+    return NULL;
+    }
+
+EXPORT_C void CPbkContactItem::RemoveField
+        (TInt aIndex)
+    {
+    PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+    __ASSERT_DEBUG(aIndex >= 0 && aIndex < CardFields().Count(),
+        Panic(EPanicPreCond_RemoveField));
+    PBK_DEBUG_ONLY(TInt old_myCount = CardFields().Count());
+    PBK_DEBUG_ONLY(TInt old_otherCount = iItem->CardFields().Count());
+
+    CContactItemField* field = &(CardFields()[aIndex].ItemField());
+    TInt i;
+    const TInt fieldCount = iItem->CardFields().Count();
+    for (i=0; i < fieldCount; ++i)
+        {
+        if (&iItem->CardFields()[i] == field)
+            {
+            break;
+            }
+        }
+    // Field must be found
+    __ASSERT_DEBUG(i < iItem->CardFields().Count(), Panic(EPanicLogic_RemoveField));
+    iItem->RemoveField(i);
+
+    iFields.Delete(aIndex);
+
+    __ASSERT_DEBUG(CardFields().Count() == old_myCount-1,
+        Panic(EPanicPostCond_RemoveField));
+    __ASSERT_DEBUG(iItem->CardFields().Count() == old_otherCount-1,
+        Panic(EPanicPostCond_RemoveField));
+    }
+
+
+EXPORT_C TPbkContactItemField& CPbkContactItem::AddFieldL
+        (CPbkFieldInfo& aFieldInfo)
+    {
+    PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+    PBK_DEBUG_ONLY(TInt old_Count = CardFields().Count());
+
+    // Create new contact model field with help from aFieldInfo
+    CContactItemField* itemField = aFieldInfo.CreateFieldL();
+    CleanupStack::PushL(itemField);
+
+    // Create and initialize a new Phonebook field object.
+    TPbkContactItemField pbkField(itemField,&aFieldInfo);
+
+    // Try to make room to iFields for the new Phonebook field. This call makes
+    // this function leave-safe, see *)
+    iFields.SetReserveL(iFields.Count()+1);
+
+    // Check that calling SetReserveL doesn't break the class invariant.
+    // It shouldn't because it doesnt change iFields.Count().
+    __TEST_INVARIANT;
+
+    // Add the contact model field to iItem
+    iItem->AddFieldL(*itemField);
+    CleanupStack::Pop(itemField);  // itemField now owned by iItem
+
+    // Here the invariant doesn't hold
+
+    // Insert the new Phonebook field.
+    // *) This call is guaranteed NOT to leave because we have succesfully
+    // reserved space to iFields with the SetReserveL call above.
+    TInt index = InsertionPos(pbkField);
+    iFields.InsertL(index, pbkField);
+
+    TPbkContactItemField& newField = iFields[index];
+
+    //PostCond:
+    __ASSERT_DEBUG(&newField.ItemField() == itemField,
+        Panic(EPanicPostCond_AddFieldL));
+    __ASSERT_DEBUG(newField.FieldInfo().IsSame(aFieldInfo),
+        Panic(EPanicPostCond_AddFieldL));
+    __ASSERT_DEBUG(iFields.Count() == old_Count+1,
+        Panic(EPanicPostCond_AddFieldL));
+    __ASSERT_DEBUG(index == iFields.Count()-1 ||
+        iFields[index+1].Compare(iFields[index]) > 0,
+        Panic(EPanicPostCond_AddFieldL));
+
+    return newField;
+    }
+
+EXPORT_C TBool CPbkContactItem::CanAcceptDataOfType
+        (CPbkFieldInfo& aFieldInfo) const
+    {
+    PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+
+    // Search for an empty field of type aFieldInfo
+    const TInt fieldCount = CardFields().Count();
+    TInt countOfFieldsOfSameType = 0;
+    for (TInt i=0; i < fieldCount; ++i)
+        {
+        const TPbkContactItemField& f = iFields[i];
+        if (f.FieldInfo().IsSame(aFieldInfo))
+            {
+            ++countOfFieldsOfSameType;
+            if (f.IsEmpty())
+                {
+                // Empty field of same type found
+                return ETrue;
+                }
+            }
+        }
+
+    // Check if a new field can be added
+    if (countOfFieldsOfSameType == 0 ||
+         aFieldInfo.Multiplicity()==EPbkFieldMultiplicityMany)
+        {
+        // New field can be added
+        return ETrue;
+        }
+
+    // Out of luck
+    return EFalse;
+    }
+
+EXPORT_C TPbkContactItemField* CPbkContactItem::AddOrReturnUnusedFieldL
+        (CPbkFieldInfo& aFieldInfo)
+    {
+    PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+
+    TPbkContactItemField* field = NULL;
+
+    // Search for an empty field of type aFieldInfo
+    const TInt fieldCount = CardFields().Count();
+    TInt countOfFieldsOfSameType = 0;
+    for (TInt i=0; i < fieldCount; ++i)
+        {
+        TPbkContactItemField& f = iFields[i];
+        if (f.FieldInfo().IsSame(aFieldInfo))
+            {
+            ++countOfFieldsOfSameType;
+            if (f.IsEmpty())
+                {
+                // Empty field of same type found
+                field = &f;
+                break;
+                }
+            }
+        }
+
+    if (!field)
+        {
+        // Empty field of same type was not found
+        if (countOfFieldsOfSameType == 0 ||
+             aFieldInfo.Multiplicity()==EPbkFieldMultiplicityMany)
+            {
+            // Add a new field
+            field = &AddFieldL(aFieldInfo);
+            }
+        }
+
+    return field;
+    }
+
+EXPORT_C void CPbkContactItem::UpdateFieldSetL
+        (const CPbkFieldsInfo& aFieldsInfo)
+    {
+    //PreCond:
+    __ASSERT_DEBUG(iItem, Panic(EPanicPreCond_UpdateFieldSetL));
+    // Don't test invariant, because this function needs to be called when
+    // the invariant is broken!
+
+    // Recreate field array like in ConstructL
+    CreateFieldArrayL(*iItem, aFieldsInfo);
+
+    __TEST_INVARIANT;
+    }
+
+EXPORT_C CPbkFieldArray& CPbkContactItem::CardFields() const
+    {
+    PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+    return const_cast<CPbkFieldArray&>(iFields);
+    }
+
+
+EXPORT_C TUid CPbkContactItem::Type() const
+    {
+    PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+    return iItem->Type();
+    }
+
+
+EXPORT_C TContactItemId CPbkContactItem::Id() const
+    {
+    PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+    return iItem->Id();
+    }
+
+EXPORT_C CContactIdArray* CPbkContactItem::GroupsJoinedLC() const
+    {
+    PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+    __ASSERT_ALWAYS(iItem->Type() == KUidContactCard,
+        Panic(EPanicPreCond_GroupsJoinedLC));
+    return static_cast<const CContactCard*>(iItem)->GroupsJoinedLC();
+    }
+
+TInt CPbkContactItem::PbkFieldCount() const
+    {
+    return iFields.Count();
+    }
+
+MPbkFieldData& CPbkContactItem::PbkFieldAt(TInt aIndex)
+    {
+    // PreCond: iFields will __ASSERT_ALWAYS aIndex validity
+    return iFields[aIndex];
+    }
+
+const MPbkFieldData& CPbkContactItem::PbkFieldAt(TInt aIndex) const
+    {
+    // PreCond: iFields will __ASSERT_ALWAYS aIndex validity
+    return iFields[aIndex];
+    }
+
+void CPbkContactItem::PrepareForSaveL()
+    {
+    PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+
+    // check that there is the syncronization field
+    // otherwise add the syncronization field
+    TPbkContactItemField* syncField = FindField(EPbkFieldIdSyncronization);
+    if (!syncField)
+        {
+        // add the syncronization field to the contact
+        CPbkContactEngine* engine = CPbkContactEngine::Static();
+        if (engine)
+            {
+            CPbkFieldInfo* syncFieldInfo = engine->FieldsInfo().Find(
+                EPbkFieldIdSyncronization);
+            if (syncFieldInfo)
+                {
+                // add syncronization field to contact - compulsory
+                AddFieldL(*syncFieldInfo);
+                }
+            }
+        }
+
+    for (TInt i=iFields.Count()-1; i >= 0; --i)
+        {
+        TPbkContactItemField& field = iFields[i];
+
+        // check that syncronization field has correct value
+        if (field.FieldInfo().FieldId() == EPbkFieldIdSyncronization)
+            {
+            // check that theres private, public or none text in the field
+            // use the default if incorrect or no value
+            const TDesC& fieldtext = field.TextStorage()->Text();
+            // safely detect whether theres syncronization setting in the field
+            if (!(!fieldtext.CompareF(KPbkContactSyncPrivate) ||
+                !fieldtext.CompareF(KPbkContactSyncPublic) ||
+                !fieldtext.CompareF(KPbkContactSyncNoSync)))
+                {
+                // set default sync setting to field
+                field.TextStorage()->SetTextL(KPbkContactSyncPrivate);
+                }
+            }
+
+        field.PrepareForSaveL();
+        if (field.HasInvalidDate())
+            {
+            RemoveField(i);
+            }
+        }
+    }
+
+void CPbkContactItem::PrepareAfterLoadL()
+    {
+    PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+    for (TInt i=iFields.Count()-1; i >= 0; --i)
+        {
+        TPbkContactItemField& field = iFields[i];
+        field.PrepareAfterLoadL();
+        if (field.HasInvalidDate())
+            {
+            RemoveField(i);
+            }
+        }
+    }
+
+/**
+ * Class invariant.
+ */
+EXPORT_C void CPbkContactItem::__DbgTestInvariant() const
+    {
+#ifdef _DEBUG
+    // Check proper construction
+    __ASSERT_DEBUG(iItem, Panic(EPanicInvariant_Pointer));
+
+    // Check field counts
+    __ASSERT_DEBUG(iItem->CardFields().Count() >= iFields.Count(),
+        Panic(EPanicInvariant_Count));
+
+    TInt phoneDefaultCount = 0;
+    TInt smsDefaultCount = 0;
+    TInt emailDefaultCount = 0;
+    TInt voiceTagFieldCount = 0;
+
+    CPbkContactEngine* engine = CPbkContactEngine::Static();
+
+    // Scan all fields
+    TInt i;
+    const TInt fieldCount = iFields.Count();
+    for (i=0; i < fieldCount; ++i)
+        {
+        const TPbkContactItemField& pbkField = iFields[i];
+
+        // Check field info for all fields
+        if (engine)
+            {
+            const CPbkFieldInfo* fieldInfo =
+                engine->FieldsInfo().Find(pbkField.ItemField());
+            __ASSERT_DEBUG(fieldInfo && fieldInfo->IsSame(pbkField.FieldInfo()),
+                           Panic(EPanicInvariant_FieldInfo));
+            }
+
+        // Search field from iItem's fieldset
+        TInt j;
+        const TInt itemFieldCount = iItem->CardFields().Count();
+        for (j = 0; j < itemFieldCount; ++j)
+            {
+            CContactItemField& field = iItem->CardFields()[j];
+            // Check if field found
+            if(&pbkField.ItemField() == &field)
+                {
+                break;
+                }
+            }
+        // field must be found
+        __ASSERT_DEBUG(j < iItem->CardFields().Count(),
+            Panic(EPanicInvariant_Field));
+
+        // Update default field counts
+        TInt prefCount = 0;
+        TInt smsCount = 0;
+        TInt voiceTagCount = 0;
+        TInt videoTagCount = 0;
+        const CContentType& contentType = pbkField.ItemField().ContentType();
+        for (TInt t = 0; t < contentType.FieldTypeCount(); ++t)
+            {
+            if (contentType.FieldType(t) == KUidPbkDefaultFieldPref)
+                ++prefCount;
+            else if (contentType.FieldType(t) == KUidPbkDefaultFieldSms)
+                ++smsCount;
+            else if (contentType.FieldType(t) == KUidContactsVoiceDialField)
+                ++voiceTagCount;
+            else if (contentType.FieldType(t) == KUidPbkDefaultFieldVideo)
+                ++videoTagCount;
+            }
+        __ASSERT_DEBUG(prefCount <= 2, Panic(EPanicInvariant_PrefCount));
+        __ASSERT_DEBUG(smsCount <= 1, Panic(EPanicInvariant_SmsCount));
+        __ASSERT_DEBUG(prefCount < 2 || smsCount == 1,
+            Panic(EPanicInvariant_PrefSmsCount));
+        __ASSERT_DEBUG(voiceTagCount <= 1,
+            Panic(EPanicInvariant_VoiceTagCount));
+        __ASSERT_DEBUG(videoTagCount <= 1,
+            Panic(EPanicInvariant_VideoTagCount));
+
+        if (pbkField.FieldInfo().IsPhoneNumberField() && prefCount >= 1)
+            {
+            if (smsCount == 1)
+                {
+                ++smsDefaultCount;
+                }
+            if ((prefCount==1 && smsCount==0) || (prefCount==2 && smsCount==1))
+                {
+                ++phoneDefaultCount;
+                }
+            }
+        if (pbkField.FieldInfo().FieldId() == EPbkFieldIdEmailAddress &&
+            prefCount==1)
+            {
+            ++emailDefaultCount;
+            }
+        if (voiceTagCount > 0)
+            {
+            ++voiceTagFieldCount;
+            }
+        }
+
+    // Check default counts: only one default per category allowed
+    __ASSERT_DEBUG(phoneDefaultCount <= 1,
+        Panic(EPanicInvariant_PhoneDefaultCount));
+    __ASSERT_DEBUG(smsDefaultCount <= 1,
+        Panic(EPanicInvariant_SmsDefaultCount));
+    __ASSERT_DEBUG(emailDefaultCount <= 1,
+        Panic(EPanicInvariant_EmailDefaultCount));
+    __ASSERT_DEBUG(voiceTagFieldCount <= 1,
+        Panic(EPanicInvariant_VoiceTagFieldCount));
+
+    // Test field sorting
+    for (i = 0; i < iFields.Count()-1; ++i)
+        {
+        __ASSERT_DEBUG(iFields[i].Compare(iFields[i+1]) <= 0,
+            Panic(EPanicInvariant_Sorting));
+        }
+#endif
+    }
+
+void CPbkContactItem::CreateFieldArrayL
+        (CContactItem& aContactItem,
+        const CPbkFieldsInfo& aFieldsInfo)
+    {
+    const TInt fieldCount = aContactItem.CardFields().Count();
+    iFields.SetReserveL(fieldCount);
+    // Use Delete instead of Reset to keep the array buffer allocated above
+    iFields.Delete(0, iFields.Count());
+    CContactItemFieldSet& fieldSet = aContactItem.CardFields();
+
+    // Loop through all import priority levels
+    for (TPbkMatchPriorityLevel priorityLevel(aFieldsInfo.CreateMatchPriority());
+        !priorityLevel.End();
+        priorityLevel.Next())
+        {
+        // Loop through all the fields
+        for (TInt i=0; i < fieldCount; ++i)
+            {
+            CContactItemField& field = fieldSet[i];
+            CPbkFieldInfo* fieldType = aFieldsInfo.Match(field, priorityLevel);
+            if (fieldType)
+                {
+                // Check that the field has not already been added
+                const TInt fieldCount = iFields.Count();
+                TInt i;
+                for (i=0; i < fieldCount; ++i)
+                    {
+                    const TPbkContactItemField& pbkField = iFields[i];
+                    if (&pbkField.ItemField()==&field ||
+                        (fieldType->Multiplicity()==EPbkFieldMultiplicityOne &&
+                        pbkField.FieldInfo().IsSame(*fieldType)))
+                        {
+                        break;
+                        }
+                    }
+                if (i == fieldCount)
+                    {
+                    // Insert the field directly into presentation order
+                    TPbkContactItemField pbkField(&field, fieldType);
+                    iFields.InsertL(InsertionPos(pbkField), pbkField);
+                    }
+                }
+            }
+        }
+    }
+
+/**
+ * Returns insertion position for aField.
+ */
+TInt CPbkContactItem::InsertionPos
+        (const TPbkContactItemField& aField) const
+    {
+    // Search for an insertion pos using the "upper bound" algorithm.
+    TInt first = 0;
+    TInt len = iFields.Count();
+    while (len > 0)
+        {
+        const TInt half = len / 2;
+        const TInt middle = first + half;
+        if (aField.Compare(iFields[middle]) < 0)
+            {
+            len = half;
+            }
+        else
+            {
+            first = middle + 1;
+            len = len - half - 1;
+            }
+        }
+
+    // If upper bound found a match, insertion pos is after that.
+    if (first < iFields.Count() && aField.Compare(iFields[first]) == 0)
+        {
+        ++first;
+        }
+
+    // PostCond
+    __ASSERT_DEBUG(first >= 0 && first <= iFields.Count(),
+        Panic(EPanicPostCond_InsertionPos));
+    return first;
+    }
+
+// ================= OTHER EXPORTED FUNCTIONS ==============
+
+EXPORT_C TBool operator==
+        (const CPbkContactItem& aLeft, const CPbkContactItem& aRight)
+    {
+    const TInt fieldCount = aLeft.iFields.Count();
+    if (aRight.iFields.Count() != fieldCount)
+        {
+        return EFalse;
+        }
+
+    for (TInt i=0; i < fieldCount; ++i)
+        {
+        if (aLeft.iFields[i] != aRight.iFields[i])
+            {
+            return EFalse;
+            }
+        }
+
+    return ETrue;
+    }
+
+//  End of File