/*
* 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 field list box model.
 *
*/


// INCLUDE FILES
#include "emailtrace.h"
#include "CFscFieldListBoxModel.h"

// Phonebook 2
#include "MFscClipListBoxText.h"
#include "MFscFieldAnalyzer.h"
#include "CFscFieldFormatter.h"
#include "MFscContactFieldDynamicProperties.h"
#include "CFscContactFieldDynamicProperties.h"
#include <CPbk2IconArray.h>
#include "FscPresentationUtils.h"
#include "CFscPresentationContactField.h"
#include "CFscPresentationContactFieldCollection.h"
#include <MPbk2FieldPropertyArray.h>
#include <MPbk2FieldProperty.h>
#include "TFscStoreContactAnalyzer.h"
#include <pbk2rclactionutils.rsg>

// Virtual Phonebook
#include <MVPbkFieldType.h>
#include <TVPbkFieldVersitProperty.h>
#include <MVPbkContactFieldData.h>
#include <MVPbkContactStore.h>
#include <CVPbkContactManager.h>
#include <MVPbkContactFieldData.h>
#include <VPbkUtils.h>

/// Unnamed namespace for local definitions
namespace
    {

    _LIT( KCharsToReplace, "\t" );
    _LIT( KReplacementChars, " " );
    const TInt KMaxFormattedTIntLength( 15);
    const TInt KInitialBufferLength( 128);
    const TInt KGranularity( 8);

    } /// namespace


// --------------------------------------------------------------------------
// CFscFieldListBoxRow::CFscFieldListBoxRow
// --------------------------------------------------------------------------
//
inline CFscFieldListBoxRow::CFscFieldListBoxRow()
    {
    FUNC_LOG;
    }

// --------------------------------------------------------------------------
// CFscFieldListBoxRow::~CFscFieldListBoxRow
// --------------------------------------------------------------------------
//
CFscFieldListBoxRow::~CFscFieldListBoxRow()
    {
    FUNC_LOG;
    iColumns.ResetAndDestroy();
    }

// --------------------------------------------------------------------------
// CFscFieldListBoxRow::NewL
// --------------------------------------------------------------------------
//
CFscFieldListBoxRow* CFscFieldListBoxRow::NewL()
    {
    FUNC_LOG;
    return new( ELeave ) CFscFieldListBoxRow;
    }

// --------------------------------------------------------------------------
// CFscFieldListBoxRow::ColumnCount
// --------------------------------------------------------------------------
//
TInt CFscFieldListBoxRow::ColumnCount() const
    {
    FUNC_LOG;
    return iColumns.Count();
    }

// --------------------------------------------------------------------------
// CFscFieldListBoxRow::At
// --------------------------------------------------------------------------
//
TPtrC CFscFieldListBoxRow::At(TInt aColumnIndex) const
    {
    FUNC_LOG;
    return *iColumns[aColumnIndex];
    }

// --------------------------------------------------------------------------
// CFscFieldListBoxRow::AppendColumnL
// --------------------------------------------------------------------------
//
void CFscFieldListBoxRow::AppendColumnL(const TDesC& aColumnText)
    {
    FUNC_LOG;
    HBufC* buf = aColumnText.AllocLC();
    User::LeaveIfError(iColumns.Append(buf) );
    CleanupStack::Pop(buf);
    }

// --------------------------------------------------------------------------
// CFscFieldListBoxRow::TotalLength
// --------------------------------------------------------------------------
//
TInt CFscFieldListBoxRow::TotalLength() const
    {
    FUNC_LOG;
    TInt result = 0;
    const TInt count = iColumns.Count();
    for (TInt i = 0; i < count; ++i)
        {
        result += At(i).Length();
        }
    return result;
    }

// --------------------------------------------------------------------------
// CFscFieldListBoxRow::MaxColumnLength
// --------------------------------------------------------------------------
//
TInt CFscFieldListBoxRow::MaxColumnLength() const
    {
    FUNC_LOG;
    TInt result = 0;
    const TInt count = iColumns.Count();
    for (TInt i = 0; i < count; ++i)
        {
        result = Max(result, At(i).Length());
        }
    return result;
    }

// --------------------------------------------------------------------------
// CFscFieldListBoxModel::CFscFieldListBoxModel
// --------------------------------------------------------------------------
//
inline CFscFieldListBoxModel::CFscFieldListBoxModel(TParams& aParams) :
    iRows(KGranularity), iParams(aParams)
    {
    FUNC_LOG;
    }

// --------------------------------------------------------------------------
// CFscFieldListBoxModel::~CFscFieldListBoxModel
// --------------------------------------------------------------------------
//
CFscFieldListBoxModel::~CFscFieldListBoxModel()
    {
    FUNC_LOG;
    iRows.ResetAndDestroy();
    delete iColumnBuf;
    delete iLineBuf;
    delete iFieldFormatter;
    delete iDynamicProperties;
    }

// --------------------------------------------------------------------------
// CFscFieldListBoxModel::NewL
// --------------------------------------------------------------------------
//
CFscFieldListBoxModel* CFscFieldListBoxModel::NewL(TParams& aParams)
    {
    FUNC_LOG;
    CFscFieldListBoxModel* self = new ( ELeave ) CFscFieldListBoxModel( aParams );
    CleanupStack::PushL(self);
    self->ConstructL(aParams);
    CleanupStack::Pop(self);
    return self;
    }

// --------------------------------------------------------------------------
// CFscFieldListBoxModel::ConstructL
// --------------------------------------------------------------------------
//
void CFscFieldListBoxModel::ConstructL(TParams& aParams)
    {
    FUNC_LOG;
    iFieldFormatter = CFscFieldFormatter::NewL(aParams.iFieldProperties,
            aParams.iContactManager.FieldTypes() );
    iFieldFormatter->SetTimeFormatL(aParams.iTimeFormat);
    iLineBuf = HBufC::NewL(KInitialBufferLength);
    iColumnBuf = HBufC::NewL(KInitialBufferLength);
    iDynamicProperties = aParams.iDynamicProperties;
    }

// --------------------------------------------------------------------------
// CFscFieldListBoxModel::AppendRowL
// --------------------------------------------------------------------------
//
void CFscFieldListBoxModel::AppendRowL(CFscFieldListBoxRow* aLine)
    {
    FUNC_LOG;
    ExpandBuffersL( *aLine);
    iRows.AppendL(aLine);
    }

// --------------------------------------------------------------------------
// CFscFieldListBoxModel::SetClipper
// --------------------------------------------------------------------------
//
void CFscFieldListBoxModel::SetClipper(MFscClipListBoxText& aTextClipper)
    {
    FUNC_LOG;
    this->iTextClipper = &aTextClipper;
    }

// --------------------------------------------------------------------------
// CFscFieldListBoxModel::FormatFieldsL
// --------------------------------------------------------------------------
//
void CFscFieldListBoxModel::FormatFieldsL()
    {
    FUNC_LOG;
    // Format all the fields and add lines to iTextArray
    const TInt fieldCount = iParams.iFields.FieldCount();
    for (TInt i=0; i < fieldCount; ++i)
        {
        FormatFieldL(iParams.iFields.At(i), iParams);
        }
    }

// --------------------------------------------------------------------------
// CFscFieldListBoxModel::MdcaCount
// --------------------------------------------------------------------------
//
TInt CFscFieldListBoxModel::MdcaCount() const
    {
    FUNC_LOG;
    return iRows.Count();
    }

// --------------------------------------------------------------------------
// CFscFieldListBoxModel::MdcaPoint
// --------------------------------------------------------------------------
//
TPtrC16 CFscFieldListBoxModel::MdcaPoint(TInt aIndex) const
    {
    FUNC_LOG;
    const TText KSeparator = '\t';
    TPtr rowText(iLineBuf->Des() );
    rowText.Zero();

    const CFscFieldListBoxRow& row = *iRows[aIndex];
    const TInt columnCount = row.ColumnCount();
    for (TInt columnIndex = 0; columnIndex < columnCount; ++columnIndex)
        {
        TPtr columnText(iColumnBuf->Des() );
        columnText.Copy(row.At(columnIndex) );

        // Clip the column if required
        if (iTextClipper && columnIndex == EContentColumn && aIndex
                < iParams.iFields.FieldCount() )
            {
            TRAP_IGNORE( ClipTextL(iParams.iFields.At(aIndex), aIndex, columnText,
                    columnIndex) );
            }

        // Append the column and separator to the formatted row
        rowText.Append(columnText);
        rowText.Append(KSeparator);
        }

    return rowText;
    }

// --------------------------------------------------------------------------
// CFscFieldListBoxModel::FormatFieldL
// --------------------------------------------------------------------------
//
void CFscFieldListBoxModel::FormatFieldL(
        const CFscPresentationContactField& aField, TParams& aParams)
    {
    FUNC_LOG;
    // Figure out whether the field should be shown
    const MFscFieldAnalyzer* fieldAnalyzer = aParams.iFieldAnalyzer;
    const MFscContactFieldDynamicProperties* dynamicProps =
            iDynamicProperties;

    TBool showField = ETrue;
    if (fieldAnalyzer && fieldAnalyzer->IsHiddenField(aField) || dynamicProps
            && dynamicProps->IsHiddenField(aField) )
        {
        showField = EFalse;
        }

    if (showField)
        {
        CFscFieldListBoxRow* row = CFscFieldListBoxRow::NewL();
        CleanupStack::PushL(row);

        // Get master field type list and match field's type against it
        const MVPbkFieldTypeList* masterFieldTypeList =
                &iParams.iContactManager.FieldTypes();

        const MVPbkFieldType* fieldType = VPbkUtils::MatchFieldType(
                *masterFieldTypeList, aField);

        TPtr columnBuf(iColumnBuf->Des());
        AppendIconsToBeginningL(aField, *fieldType, *row, aParams);
        AppendFieldLabelL(aField, *row, columnBuf);
        AppendFieldContentL(aField, *fieldType, *row, columnBuf);

        // Expand row formatting buffer if required
        ExpandBuffersL(*row);

        // Add the row
        iRows.AppendL(row);
        CleanupStack::Pop(row);
        }
    }

// --------------------------------------------------------------------------
// CFscFieldListBoxModel::ExpandBuffersL
// --------------------------------------------------------------------------
//
void CFscFieldListBoxModel::ExpandBuffersL(const CFscFieldListBoxRow& aRow)
    {
    FUNC_LOG;
    // Row formatting buffer
    const TInt rowLength = aRow.TotalLength() + aRow.ColumnCount(); // for separator characters

    if (rowLength > iLineBuf->Des().MaxLength())
        {
        iLineBuf = iLineBuf->ReAllocL(rowLength);
        }

    ExpandColumnBufferL(aRow.MaxColumnLength() );
    }

// --------------------------------------------------------------------------
// CFscFieldListBoxModel::ExpandColumnBufferL
// --------------------------------------------------------------------------
//
TPtr CFscFieldListBoxModel::ExpandColumnBufferL(TInt aRequiredLength)
    {
    FUNC_LOG;
    if (aRequiredLength > iColumnBuf->Des().MaxLength() )
        {
        iColumnBuf = iColumnBuf->ReAllocL(aRequiredLength);
        }
    return (iColumnBuf->Des() );
    }

// --------------------------------------------------------------------------
// CFscFieldListBoxModel::ClipText
// Clip text from beginning if field is numeric field or e-mail field.
// --------------------------------------------------------------------------
//
inline void CFscFieldListBoxModel::ClipTextL(
        const CFscPresentationContactField& aField, TInt aIndex,
        TPtr& aColumnText, TInt aColumnIndex) const
    {
    FUNC_LOG;
    TFscStoreContactAnalyzer analyzer(iParams.iContactManager, NULL);
    TBool clip = analyzer.IsFieldTypeIncludedL(aField,
            R_FSC_PHONENUMBER_SELECTOR);

    // Clip if required
    if (clip)
        {
        iTextClipper->ClipFromBeginning(aColumnText, aIndex, aColumnIndex);
        }
    }

// --------------------------------------------------------------------------
// CFscFieldListBoxModel::AppendFieldLabelL
// Appends field label. Removes any listbox separator characters.
// --------------------------------------------------------------------------
//
inline void CFscFieldListBoxModel::AppendFieldLabelL(
        const CFscPresentationContactField& aField,
        CFscFieldListBoxRow& aRow, TPtr& aColumnBuf)
    {
    FUNC_LOG;
    aColumnBuf.Set(ExpandColumnBufferL(aField.FieldLabel().Length() ) );
    aColumnBuf.Zero();
    FscPresentationUtils::AppendAndReplaceChars(aColumnBuf,
            aField.FieldLabel(), KCharsToReplace, KReplacementChars);
    // Replace characters that can not be displayed correctly
    FscPresentationUtils::ReplaceNonGraphicCharacters(aColumnBuf, ' ');
    aRow.AppendColumnL(aColumnBuf);
    }

// --------------------------------------------------------------------------
// CFscFieldListBoxModel::AppendFieldContentL
// Appends field content.
// --------------------------------------------------------------------------
//
inline void CFscFieldListBoxModel::AppendFieldContentL(
        const CFscPresentationContactField& aField,
        const MVPbkFieldType& aFieldType, CFscFieldListBoxRow& aRow,
        TPtr& aColumnBuf)
    {
    FUNC_LOG;
    TPtrC fieldText(iFieldFormatter->FormatFieldContentL(aField, aFieldType) );
    aColumnBuf.Set(ExpandColumnBufferL(fieldText.Length() ) );
    aColumnBuf.Zero();
    FscPresentationUtils::AppendAndReplaceChars(aColumnBuf, fieldText,
            KCharsToReplace, KReplacementChars);
    // Replace characters that can not be displayed correctly
    FscPresentationUtils::ReplaceNonGraphicCharacters(aColumnBuf, ' ');
    aRow.AppendColumnL(aColumnBuf);
    }

// --------------------------------------------------------------------------
// CFscFieldListBoxModel::AppendIconsToBeginningL
// Adds icons to the beginning.
// --------------------------------------------------------------------------
//
inline void CFscFieldListBoxModel::AppendIconsToBeginningL(
        const CFscPresentationContactField& /*aField*/,
        const MVPbkFieldType& aFieldType, CFscFieldListBoxRow& aRow,
        TParams& aParams)
    {
    FUNC_LOG;
    TBuf<KMaxFormattedTIntLength> iconText;

    // Format icon index
    TInt iconIndex = aParams.iIconArray.FindIcon(iParams.iDefaultIconId);
    const MPbk2FieldProperty* property =
            aParams.iFieldProperties.FindProperty(aFieldType);
    if (property)
        {
        iconIndex = aParams.iIconArray.FindIcon(property->IconId() );
        }

    iconText.Num(iconIndex);
    aRow.AppendColumnL(iconText);
    }

// --------------------------------------------------------------------------
// CFscFieldListBoxModel::AppendIconsToEndL
// Adds additional icons to the end.
// --------------------------------------------------------------------------
//
inline void CFscFieldListBoxModel::AppendIconsToEndL(
        const CFscPresentationContactField& aField,
        CFscFieldListBoxRow& aRow, TParams& aParams)
    {
    FUNC_LOG;
    if (aParams.iFieldAnalyzer)
        {
        // Check and add speed dial icon
        if (aParams.iFieldAnalyzer->HasSpeedDialL(aField.StoreField() ) )
            {
            TBuf<KMaxFormattedTIntLength> iconText;
            iconText.Num(aParams.iIconArray.FindIcon(TFscAppIconId(EPbk2qgn_indi_qdial_add) ) );
            aRow.AppendColumnL(iconText);
            }
        }
    }

//  End of File

