/*
* Copyright (c) 2002-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 contact view sort policy.
*
*/


#include "CPbk2ContactViewSortPolicy.h"

// Phonebook2
#include "CPbk2SortKeyArray.h"
#include "RPbk2LocalizedResourceFile.h"
#include "Pbk2DataCaging.hrh"
#include <Pbk2UIPolicyRes.rsg>

// Virtual Phonebook
#include <MVPbkFieldType.h>
#include <MVPbkViewContact.h>
#include <MVPbkBaseContactField.h>
#include <MVPbkContactFieldTextData.h>
#include <MVPbkBaseContactFieldCollection.h>
#include <CVPbkContactManager.h>
#include <CVPbkFieldTypeSelector.h>
#include <CVPbkFieldFilter.h>
#include <CVPbkSortOrder.h>

// System includes
#include <coemain.h>
#include <barsread.h>
#include <SortUtil.h>

// Debugging headers
#include <Pbk2Profile.h>


/// Unnamed namespace for local definitions
namespace {

_LIT(KResourceFile, "Pbk2UIPolicyRes.rsc");
const TInt KNegative = -1;
const TInt KPositive = 1;

/**
 * Sort key array.
 */
class TPbk2SortKeyArray : public MSortKeyArray
    {
    public: // Interface

        /**
         * Constructor.
         *
         * @param aArray    Array.
         */
        TPbk2SortKeyArray(
                const MVPbkSortKeyArray& aArray );

        /**
         * Returns the count of the keys.
         *
         * @return  Count of the keys.
         */
        TInt SortKeyCount() const
            {
            return iArray.Count();
            }

        /**
         * Returns the key at aIndex.
         *
         * @param aIndex    Index to query.
         * @return  Key at queried index.
         */
        TSortKey SortKeyAt(
                TInt aIndex ) const;

    private: // Data
        /// Ref: Array
        const MVPbkSortKeyArray& iArray;

    };

// --------------------------------------------------------------------------
// TPbk2SortKeyArray::TPbk2SortKeyArray
// --------------------------------------------------------------------------
//
TPbk2SortKeyArray::TPbk2SortKeyArray( const MVPbkSortKeyArray& aArray ) :
        iArray( aArray )
    {
    }

// --------------------------------------------------------------------------
// TPbk2SortKeyArray::SortKeyAt
// --------------------------------------------------------------------------
//
TSortKey TPbk2SortKeyArray::SortKeyAt( TInt aIndex ) const
    {
    TSortKeyType sortKeyType( ESortKeyBasic );
    if ( iArray.SortKeyAt( aIndex ).Type() == EVPbkSortKeyPronounciation )
        {
        sortKeyType = ESortKeyPronounciation;
        }

    return TSortKey( iArray.SortKeyAt( aIndex ).Text(), sortKeyType );
    }

} /// namespace


// --------------------------------------------------------------------------
// CPbk2ContactViewSortPolicy::CPbk2ContactViewSortPolicy
// --------------------------------------------------------------------------
//
CPbk2ContactViewSortPolicy::CPbk2ContactViewSortPolicy()
    {
    }

// --------------------------------------------------------------------------
// CPbk2ContactViewSortPolicy::~CPbk2ContactViewSortPolicy
// --------------------------------------------------------------------------
//
CPbk2ContactViewSortPolicy::~CPbk2ContactViewSortPolicy()
    {
    delete iPronunciationFieldSelector;
    delete iRightSortKeyArray;
    delete iLeftSortKeyArray;
    delete iSortUtil;
    delete iSortOrder;
    }

// --------------------------------------------------------------------------
// CPbk2ContactViewSortPolicy::NewL
// --------------------------------------------------------------------------
//
CPbk2ContactViewSortPolicy* CPbk2ContactViewSortPolicy::NewL
        ( TParam* aParam )
    {
    CPbk2ContactViewSortPolicy* self =
        new ( ELeave ) CPbk2ContactViewSortPolicy;
    CleanupStack::PushL( self );
    self->ConstructL( aParam );
    CleanupStack::Pop( self );
    return self;
    }

// --------------------------------------------------------------------------
// CPbk2ContactViewSortPolicy::ConstructL
// --------------------------------------------------------------------------
//
void CPbk2ContactViewSortPolicy::ConstructL( TParam* aParam )
    {
    iSortUtil = CSortUtil::NewL();

    if ( aParam )
        {
        iSortPolicyParameterReceived = ETrue;

        iLeftSortKeyArray = CPbk2SortKeyArray::NewL();
        iRightSortKeyArray = CPbk2SortKeyArray::NewL();

        iSortOrder = CVPbkSortOrder::NewL(aParam->iSortOrder);
        iFieldMapper.SetSortOrder(*iSortOrder);

        RPbk2LocalizedResourceFile resFile(aParam->iFs);
        resFile.OpenLC( KPbk2RomFileDrive, KDC_RESOURCE_FILES_DIR,
            KResourceFile );

        HBufC8* selectorBuf = resFile.AllocReadLC
            ( R_PRONUNCIATION_FIELD_SELECTOR );
        TResourceReader reader;
        reader.SetBuffer( selectorBuf );
        iPronunciationFieldSelector = CVPbkFieldTypeSelector::NewL
            ( reader, aParam->iFieldTypes );

        CleanupStack::PopAndDestroy( 2 ); // buffer, resFile

        }
    }

// --------------------------------------------------------------------------
// CPbk2ContactViewSortPolicy::SetSortOrderL
// --------------------------------------------------------------------------
//
void CPbk2ContactViewSortPolicy::SetSortOrderL
        ( const MVPbkFieldTypeList& aSortOrder )
    {
    if ( !iSortPolicyParameterReceived )
        {
        // This class has been initialized without TParam
        User::Leave( KErrNotSupported );
        }

    CVPbkSortOrder* sortOrder = CVPbkSortOrder::NewL( aSortOrder );
    delete iSortOrder;
    iSortOrder = sortOrder;
    iFieldMapper.SetSortOrder( *iSortOrder );
    }

// --------------------------------------------------------------------------
// CPbk2ContactViewSortPolicy::SortStartL
// --------------------------------------------------------------------------
//
void CPbk2ContactViewSortPolicy::SortStartL()
    {
    if ( !iSortPolicyParameterReceived )
        {
        // This class has been initialized without TParam
        User::Leave( KErrNotSupported );
        }

    iLeftSortKeyArray->Reset();
    iRightSortKeyArray->Reset();

    const TInt typeCount( iSortOrder->FieldTypeCount() );
    for ( TInt i( 0 ); i < typeCount; ++i )
        {
        const MVPbkFieldType& fieldType = iSortOrder->FieldTypeAt( i );
        if ( iPronunciationFieldSelector->IsFieldTypeIncluded( fieldType ) )
            {
            iLeftSortKeyArray->AppendL(
                TSortKey( KNullDesC, ESortKeyPronounciation ) );
            iRightSortKeyArray->AppendL(
                TSortKey( KNullDesC, ESortKeyPronounciation ) );
            }
        else
            {
            iLeftSortKeyArray->AppendL(
                TSortKey( KNullDesC, ESortKeyBasic ) );
            iRightSortKeyArray->AppendL(
                TSortKey( KNullDesC, ESortKeyBasic ) );
            }
        }
    }

// --------------------------------------------------------------------------
// CPbk2ContactViewSortPolicy::SortCompleted
// --------------------------------------------------------------------------
//
void CPbk2ContactViewSortPolicy::SortCompleted()
    {
    iLeftSortKeyArray->Reset();
    iRightSortKeyArray->Reset();
    }

// --------------------------------------------------------------------------
// CPbk2ContactViewSortPolicy::CompareContacts
// --------------------------------------------------------------------------
//
TInt CPbk2ContactViewSortPolicy::CompareContacts
        ( const MVPbkViewContact& aLhs, const MVPbkViewContact& aRhs )
    {
    TInt ret = 0;

    if ( iSortPolicyParameterReceived )
        {
        // Change the text in the sortkeys to correspond
        // fields in the contacts

        TInt i = 0;

PBK2_PROFILE_START( Pbk2Profile::ESortPolicyCompareContacts );

        iFieldMapper.SetContactFields( aLhs.Fields() );
        const TInt lhsCount = iFieldMapper.FieldCount();
        for ( i = 0; i < lhsCount; ++i )
            {
            const MVPbkBaseContactField* lhsField =
                iFieldMapper.FieldAt( i );
            if ( lhsField )
                {
                iLeftSortKeyArray->SetText( MVPbkContactFieldTextData::Cast
                    ( lhsField->FieldData() ).Text(), i );
                }
            else
                {
                iLeftSortKeyArray->SetText( KNullDesC, i );
                }
            }

        iFieldMapper.SetContactFields( aRhs.Fields() );
        const TInt rhsCount = iFieldMapper.FieldCount();
        for ( i = 0; i < rhsCount; ++i )
            {
            const MVPbkBaseContactField* rhsField =
                iFieldMapper.FieldAt( i );
            if ( rhsField )
                {
                iRightSortKeyArray->SetText( MVPbkContactFieldTextData::Cast
                    ( rhsField->FieldData() ).Text(), i );
                }
            else
                {
                iRightSortKeyArray->SetText( KNullDesC, i );
                }
            }

PBK2_PROFILE_END( Pbk2Profile::ESortPolicyCompareContacts );


PBK2_PROFILE_START( Pbk2Profile::ESortPolicySortUtil );

        TInt result( iSortUtil->Interface()->CompareItems
            ( *iLeftSortKeyArray, *iRightSortKeyArray ) );

PBK2_PROFILE_END( Pbk2Profile::ESortPolicySortUtil );

        ret = PostProcessResult( result );
        }

    return ret;
    }

// --------------------------------------------------------------------------
// CPbk2ContactViewSortPolicy::CompareItems
// --------------------------------------------------------------------------
//
TInt CPbk2ContactViewSortPolicy::CompareItems
        ( const MVPbkSortKeyArray& aLhs,
          const MVPbkSortKeyArray& aRhs ) const
    {
    const TPbk2SortKeyArray lhsKeyArray( aLhs );
    const TPbk2SortKeyArray rhsKeyArray( aRhs );
    return iSortUtil->Interface()->CompareItems( lhsKeyArray, rhsKeyArray );
    }

// --------------------------------------------------------------------------
// CPbk2ContactViewSortPolicy::PostProcessResult
// --------------------------------------------------------------------------
//
TInt CPbk2ContactViewSortPolicy::PostProcessResult( TInt aSortUtilResult )
    {
    // With this function we correct sort util result because it does not
    // give right answers if contact is "Unnamed".
    // So here is clarified how this function corrects the result.
    // If rightside has no data left is less (-1) otherwise greater (1).
    // "<Unnamed>"  vs. "<Unnamed>" = -1,   leftside comes before rightside
    // "a"          vs. "<Unnamed>" = -1,   leftside comes before rightside
    // "<Unnamed>"  vs. "a"         = 1     rightside comes before leftside
    //
    TInt result = aSortUtilResult;
    const TInt rhsCount( iRightSortKeyArray->SortKeyCount() );
    TBool rhsHasData( EFalse );
    for ( TInt i = 0; i < rhsCount; ++i )
        {
        TSortKey key = iRightSortKeyArray->SortKeyAt( i );
        if ( key.Text().Length() > 0 )
            {
            rhsHasData = ETrue;
            break;
            }
        }

    if ( !rhsHasData )
        {
        // Here we have situation "something" vs "<Unnamed>" .
        // We want leftside to come before rightside.
        result = KNegative;
        }
    else
        {
        TBool lhsHasData( EFalse );
        const TInt lhsCount( iLeftSortKeyArray->SortKeyCount() );
        for ( TInt i = 0; i < lhsCount; ++i )
            {
            TSortKey key = iLeftSortKeyArray->SortKeyAt( i );
            if ( key.Text().Length() > 0 )
                {
                lhsHasData = ETrue;
                break;
                }
            }

        if ( !lhsHasData )
            {
            // Here we have situation "<Unnamed>" vs. "something".
            // We want rightside to come before leftside.
            result = KPositive;
            }
        }

    return result;
    }

//  End of File
