/*
* 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 Sort order manager.
*
*/


// INCLUDE FILES
#include "CPbkSortOrderManager.h"
#include <featmgr.h>
#include <bldvariant.hrh>
#include <CPbkContactEngine.h>
#include <StringLoader.h>
#include <PbkEng.rsg>
#include <barsread.h>    // TResourceReader
#include <PbkGlobalSettingFactory.h>
#include <MPbkGlobalSetting.h>
#include "PbkUID.h"
#include <PbkEngUtils.h>
#include "PbkEng.hrh"
/// Unnamed namespace for local definitions
namespace {

// CONSTANTS

// Name order setting value for First Name Last Name
// This value comes from phonebook specification (see
// qtn_phob_name_order) and it's opposite compared to
// TPbkNameOrder that is used in CenRep.
_LIT(KPbkFirstLastNameEnabled, "0");
// Value when name separator is used
_LIT(KPbkNameSeparatorUsed, "1");
// Dec value for space character
const TInt KPbkSpaceDecValue = 32;

// Separator string length is set to 4.
// Separator should be only one character long,
// but sometimes localized string or cenrep initial value
// may contain additional space characters at the end of string.
const TInt KPbkSeparatorMaxLength = 4;

#ifdef _DEBUG
// CONSTANTS
enum TPanicCode
    {
    EPanicPreCond_SetNameDisplayOrderL = 1
    };

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

// Conversion function is used because old functions
// SetNameSeparatorL() and NameSeparator() are supported.
// In old format 0 means that space character is used and in
// new format 23 stands for space character
inline TChar ConvertSeparatorCharacterToOld(TChar aFrom)
    {
    // Convert space value to 0 value.
    return (TUint(aFrom)==KPbkSpaceDecValue)? TChar(0) : aFrom;
    }

inline TChar ConvertSeparatorCharacterToNew(TChar aFrom)
    {
    // Convert 0 value to space value.
    return TUint(aFrom)==0? TChar(KPbkSpaceDecValue) : aFrom;
    }

} // namespace

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

inline CPbkSortOrderManager::CPbkSortOrderManager(RFs& aFs, TBool aSettingsVisible):
                                        iFs(aFs), iSettingsVisible(aSettingsVisible)
    {
    }

inline void CPbkSortOrderManager::ConstructL()
    {
    iPersistentSetting = PbkGlobalSettingFactory::CreatePersistentSettingL();
    iPersistentSetting->ConnectL(MPbkGlobalSetting::EGeneralSettingCategory);

    // construct name sort order
    RContactViewSortOrder sortOrder =
        DoCreateSortOrderL(PersistentNameDisplayOrderL(), iSettingsVisible);
    iSortOrder = sortOrder;
    iNameSeparator =
        ConvertSeparatorCharacterToOld(PersistentNameSeparatorCharL());
    iPersistentSetting->RegisterObserverL(this);
    }

inline void CPbkSortOrderManager::SetPersistentNameDisplayOrderL
        (CPbkContactEngine::TPbkNameOrder aNameOrder)
    {
    __ASSERT_DEBUG(
            aNameOrder == CPbkContactEngine::EPbkNameOrderLastNameFirstName ||
            aNameOrder == CPbkContactEngine::EPbkNameOrderFirstNameLastName,
            Panic(EPanicPreCond_SetNameDisplayOrderL));

    User::LeaveIfError(iPersistentSetting->Set(
        MPbkGlobalSetting::ENameOrdering, TInt(aNameOrder)));
    }

inline void CPbkSortOrderManager::
        SetPersistentNameSeparatorCharL(TChar aNameSeparatorChar)
    {
    // 1 character is appended.
    TBuf<1> string;
    string.Append(aNameSeparatorChar);
    User::LeaveIfError(iPersistentSetting->Set(
        MPbkGlobalSetting::ENameSeparatorChar, string));
    }


CPbkSortOrderManager* CPbkSortOrderManager::NewL(RFs& aFs, TBool aSettingsVisible)
    {
    CPbkSortOrderManager* self = new(ELeave) CPbkSortOrderManager(aFs, aSettingsVisible);
    CleanupStack::PushL(self);
    self->ConstructL();
    CleanupStack::Pop(self);
    return self;
    }

CPbkSortOrderManager::~CPbkSortOrderManager()
    {
    if (iPersistentSetting)
        {
        iPersistentSetting->Close();
        delete iPersistentSetting;
        }
    iSortOrder.Close();
    delete iNameOrderSetting;
    delete iNameSeparatorUsed;
    delete iInitialNameSeparatorChar;
    }

const RContactViewSortOrder& CPbkSortOrderManager::SortOrder() const
    {
    return iSortOrder;
    }

void CPbkSortOrderManager::SetNameDisplayOrderL
        (CPbkContactEngine::TPbkNameOrder aNameOrder)
    {
    // create new view sort order from aNameOrder
    RContactViewSortOrder newSortOrder = DoCreateSortOrderL(aNameOrder,
                                                            iSettingsVisible);
    CleanupClosePushL(newSortOrder);

    if (iContactView)
        {
        //retrieve the contact view sort order
        RContactViewSortOrder oldViewSortOrder;
        CleanupClosePushL(oldViewSortOrder);
        iContactView->GetSortOrderL(oldViewSortOrder);

        // try to change the contact view sort order
        iContactView->ChangeSortOrderL(newSortOrder);
        // Try to change the persistent key for name ordering
        TRAPD(err,SetPersistentNameDisplayOrderL(aNameOrder));
        if (err)
            {
            // error occurred, restore view sort order
            iContactView->ChangeSortOrderL(oldViewSortOrder);
            CleanupStack::Pop(); // oldViewSortOrder
            }
        else
            {
            CleanupStack::PopAndDestroy(); // oldViewSortOrder
            iSortOrder.Close();
            iSortOrder = newSortOrder;
            CleanupStack::Pop(); // newSortOrder
            }
        }
    else
        {
        CleanupStack::PopAndDestroy(); // newSortOrder
        }
    }

CPbkContactEngine::TPbkNameOrder CPbkSortOrderManager::NameDisplayOrder() const
    {
    // return current name display order
    for (TInt i = 0; i < iSortOrder.Count(); ++i)
        {
        if (iSortOrder[i] == KUidContactFieldFamilyName)
            {
            return CPbkContactEngine::EPbkNameOrderLastNameFirstName;
            }
        else if (iSortOrder[i] == KUidContactFieldGivenName)
            {
            return CPbkContactEngine::EPbkNameOrderFirstNameLastName;
            }
        }
    return CPbkContactEngine::EPbkNameOrderLastNameFirstName;
    }

void CPbkSortOrderManager::SetContactView
        (CContactNamedRemoteView& aContactView)
    {
    iContactView = &aContactView;
    }

void CPbkSortOrderManager::SettingChangedL(MPbkGlobalSetting::
                                                    TPbkGlobalSetting aKey)
    {
    if (aKey == MPbkGlobalSetting::ENameOrdering ||
        aKey == MPbkGlobalSetting::ENameSeparatorChar)
        {
        // Update sortorder and name separator char
        RContactViewSortOrder sortOrder =
                            DoCreateSortOrderL(PersistentNameDisplayOrderL(),
                                               iSettingsVisible);
        iSortOrder.Close();
        iSortOrder = sortOrder;

        iNameSeparator =
            ConvertSeparatorCharacterToOld(PersistentNameSeparatorCharL());
        }
    }

void CPbkSortOrderManager::SetNameSeparatorL(TChar aNameSeparator)
    {
    // 0 is converted to space character
    SetPersistentNameSeparatorCharL(
        ConvertSeparatorCharacterToNew(aNameSeparator));
    iNameSeparator = aNameSeparator;
    }

TChar CPbkSortOrderManager::NameSeparator() const
    {
    return iNameSeparator;
    }

RContactViewSortOrder CPbkSortOrderManager::DoCreateSortOrderL
        (CPbkContactEngine::TPbkNameOrder aNameOrder,
         TBool aSettingVisible)
    {
    RContactViewSortOrder sortOrder;
    CleanupClosePushL(sortOrder);
    // engine creation will assign it to the views
	
	sortOrder.AppendL(TUid::Uid(KUidContactFieldTopContactValue));
	
    if (FeatureManager::FeatureSupported(KFeatureIdChinese) &&
        !aSettingVisible)
        {
        // Chinese sort ordering
        sortOrder.AppendL(KUidContactFieldFamilyName);
        sortOrder.AppendL(KUidContactFieldGivenName);
        sortOrder.AppendL(KUidContactFieldCompanyName);
        }
    else if (FeatureManager::FeatureSupported(KFeatureIdJapanese))
        {
        // japanese sort ordering
        if (aNameOrder == CPbkContactEngine::EPbkNameOrderLastNameFirstName)
            {
            sortOrder.AppendL(KUidContactFieldFamilyNamePronunciation);
            sortOrder.AppendL(KUidContactFieldGivenNamePronunciation);
            sortOrder.AppendL(KUidContactFieldFamilyName);
            sortOrder.AppendL(KUidContactFieldGivenName);
            }
        else
            {
            sortOrder.AppendL(KUidContactFieldGivenNamePronunciation);
            sortOrder.AppendL(KUidContactFieldFamilyNamePronunciation);
            sortOrder.AppendL(KUidContactFieldGivenName);
            sortOrder.AppendL(KUidContactFieldFamilyName);
            }
        sortOrder.AppendL(KUidContactFieldCompanyName);
        }
    else
        {
        // default sort ordering
        if (aNameOrder == CPbkContactEngine::EPbkNameOrderLastNameFirstName)
            {
            sortOrder.AppendL(KUidContactFieldFamilyName);
            sortOrder.AppendL(KUidContactFieldGivenName);
            }
        else
            {
            sortOrder.AppendL(KUidContactFieldGivenName);
            sortOrder.AppendL(KUidContactFieldFamilyName);
            }
        sortOrder.AppendL(KUidContactFieldCompanyName);
        }
    sortOrder.AppendL(KUidContactFieldTemplateLabel);

    CleanupStack::Pop(); // sortOrder
    return sortOrder;
    }

CPbkContactEngine::TPbkNameOrder
    CPbkSortOrderManager::PersistentNameDisplayOrderL()
    {
    TInt nameOrder = KErrNotFound;
    User::LeaveIfError(
        iPersistentSetting->Get(MPbkGlobalSetting::ENameOrdering, nameOrder));
    CPbkContactEngine::TPbkNameOrder pbkNameOrder =
        static_cast<CPbkContactEngine::TPbkNameOrder>(nameOrder);

    // Read phonebook contact name presentation order configuration
    // if order not defined.
    if (pbkNameOrder == CPbkContactEngine::EPbkNameOrderNotDefined)
        {
        RResourceFile pbkResFile;
        // Calls CleanupClosePushL for pbkResFile.
        PbkEngUtils::FindAndOpenDefaultResourceFileLC(iFs, pbkResFile);
        TResourceReader reader;

        if(!iNameOrderSetting)
            {
            // Value 0 is first name last name and value 1 is last name first name
            reader.SetBuffer(pbkResFile.AllocReadLC(R_PBK_NAME_ORDER));
            iNameOrderSetting = reader.ReadHBufCL();
            CleanupStack::PopAndDestroy();  // R_PBK_NAME_ORDER
            }

        if (!iNameOrderSetting->Compare(KPbkFirstLastNameEnabled))
            {
            // Compare return 0 if setting order value in loaded resource is "0"
            // then first name last name order is used.
            pbkNameOrder = CPbkContactEngine::EPbkNameOrderFirstNameLastName;
            }
        else
            {
            pbkNameOrder = CPbkContactEngine::EPbkNameOrderLastNameFirstName;
            }
        CleanupStack::PopAndDestroy(1); // pbkResFile
        }
    return pbkNameOrder;
    }

TChar CPbkSortOrderManager::PersistentNameSeparatorCharL()
    {
    TBuf<KPbkSeparatorMaxLength> string;
    string.SetLength(0);
    User::LeaveIfError(iPersistentSetting->Get(
        MPbkGlobalSetting::ENameSeparatorChar, string));
    // NULL string is for undefined
    if (!string.Length() || string[0] == 0)
        {
        RResourceFile pbkResFile;
        // Calls CleanupClosePushL for pbkResFile.
        PbkEngUtils::FindAndOpenDefaultResourceFileLC(iFs, pbkResFile);
        TResourceReader reader;

        if(!iNameSeparatorUsed)
            {
            reader.SetBuffer(pbkResFile.AllocReadLC(R_PBK_NAME_SEPARATOR_USED));
            iNameSeparatorUsed = reader.ReadHBufCL();
            CleanupStack::PopAndDestroy();  // R_PBK_NAME_SEPARATOR_USED
            }
        if(!iNameSeparatorUsed->Compare(KPbkNameSeparatorUsed))
            {
            // Separator is used, use initial value
            if(!iInitialNameSeparatorChar)
                {
                reader.SetBuffer(pbkResFile.AllocReadLC(R_PBK_NAME_SEPARATOR_CHAR));
                iInitialNameSeparatorChar = reader.ReadHBufCL();
                CleanupStack::PopAndDestroy();  // R_PBK_NAME_SEPARATOR_CHAR
                }
            string.SetLength(0);
            string.Append(*iInitialNameSeparatorChar);
            }
        else if (string.Length()<KPbkSeparatorMaxLength)
            {
            // Space is used if separator character is not defined by default.
            TChar space(KPbkSpaceDecValue);
            string.SetLength(0);
            string.Append(space);
            }
        CleanupStack::PopAndDestroy(1); // pbkResFile
        }

    return TChar(string[0]);
    }

// End of File
