/*
* 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:  Selector factory for a set of predefined selectors.
*
*/


// Virtual Phonebook
#include "VPbkFieldTypeSelectorFactory.h"
#include "CVPbkFieldTypeList.h"

#include <VPbkDataCaging.hrh>
#include <CVPbkFieldTypeSelector.h>
#include <MVPbkFieldType.h>
#include <CVPbkLocalVariationManager.h>
#include <VPbkFieldTypeSelectors.rsg>
#include <RLocalizedResourceFile.h>
#include <featmgr.h>
#include <VPbkEng.rsg>
#include <spsettings.h>
#include <spproperty.h>
#include <spentry.h>

// System includes
#include <f32file.h>
#include <barsread.h>

namespace {

struct TMap
    {
    TInt iType;
    TInt iResId;
    };

const TMap KFieldMapTable[] = {
    { VPbkFieldTypeSelectorFactory::EPhoneNumberSelector, R_VPBK_PHONE_NUMBER_SELECTOR },
    { VPbkFieldTypeSelectorFactory::EMobileNumberSelector, R_VPBK_MOBILE_NUMBER_SELECTOR },
    { VPbkFieldTypeSelectorFactory::EFaxNumberSelector, R_VPBK_FAX_NUMBER_SELECTOR },
    { VPbkFieldTypeSelectorFactory::EVideoNumberSelector, R_VPBK_VIDEO_NUMBER_SELECTOR },
    { VPbkFieldTypeSelectorFactory::EPagerNumberSelector, R_VPBK_PAGER_NUMBER_SELECTOR },
    { VPbkFieldTypeSelectorFactory::EEmailAddressSelector, R_VPBK_EMAIL_ADDRESS_SELECTOR },
    { VPbkFieldTypeSelectorFactory::EEmailOverSmsSelector, R_VPBK_EMAIL_OVER_SMS_SELECTOR },
    { VPbkFieldTypeSelectorFactory::EMmsAddressSelector, R_VPBK_MMS_ADDRESS_SELECTOR },
    { VPbkFieldTypeSelectorFactory::EVoipAddressSelector, R_VPBK_VOIP_ADDRESS_SELECTOR },
    { VPbkFieldTypeSelectorFactory::EPttAddressSelector, R_VPBK_PTT_ADDRESS_SELECTOR },
    { VPbkFieldTypeSelectorFactory::ESipAddressSelector, R_VPBK_SIP_ADDRESS_SELECTOR },
    { VPbkFieldTypeSelectorFactory::ESipMsisdnAddressSelector, R_VPBK_SIP_MSISDN_ADDRESS_SELECTOR },
    { VPbkFieldTypeSelectorFactory::EThumbnailImageSelector, R_VPBK_THUMBNAIL_IMAGE_SELECTOR },
    { VPbkFieldTypeSelectorFactory::ECodImageSelector, R_VPBK_COD_IMAGE_SELECTOR },
    { VPbkFieldTypeSelectorFactory::EImageSelector, R_VPBK_IMAGE_SELECTOR },
    { VPbkFieldTypeSelectorFactory::ECodTextSelector, R_VPBK_COD_TEXT_SELECTOR },
    { VPbkFieldTypeSelectorFactory::ERingingToneSelector, R_VPBK_RINGING_TONE_SELECTOR },
    { VPbkFieldTypeSelectorFactory::EUrlAddressSelector, R_VPBK_URL_ADDRESS_SELECTOR },
    { VPbkFieldTypeSelectorFactory::ELastNameSelector, R_VPBK_LAST_NAME_SELECTOR },
    { VPbkFieldTypeSelectorFactory::EFirstNameSelector, R_VPBK_FIRST_NAME_SELECTOR },
    { VPbkFieldTypeSelectorFactory::ELastNamePronunciationSelector, R_VPBK_LAST_NAME_PRONUNCIATION_SELECTOR },
    { VPbkFieldTypeSelectorFactory::EFirstNamePronunciationSelector, R_VPBK_FIRST_NAME_PRONUNCIATION_SELECTOR },
    { VPbkFieldTypeSelectorFactory::ESynchronizationSelector, R_VPBK_SYNCHRONIZATION_SELECTOR },
    { VPbkFieldTypeSelectorFactory::EDtmfNumberSelector, R_VPBK_DTMF_NUMBER_SELECTOR },
    { VPbkFieldTypeSelectorFactory::ETopcontactSelector, R_VPBK_TOPCONTACT_SELECTOR },
    { VPbkFieldTypeSelectorFactory::EImppSelector, R_VPBK_IMPP_SELECTOR },
    { VPbkFieldTypeSelectorFactory::EFindOnMapSelector, R_VPBK_ADDRESS_SELECTOR },
    { VPbkFieldTypeSelectorFactory::EAssignFromMapSelector, R_VPBK_ADDRESS_SELECTOR },
    { VPbkFieldTypeSelectorFactory::EPagerfaxSelector, R_VPBK_PAGERFAX_SELECTOR }
    // add more selectors here
};
const TInt KFieldMapTableLength = sizeof( KFieldMapTable ) / sizeof( TMap );

/**
 * Maps selector iType and ressource id.
 *
 * @param aType Id of the predefined selector.
 * @return A matching ressource id or KErrNotFound.
 */
TInt MapFieldTypeSelectorToRessourceId(
        VPbkFieldTypeSelectorFactory::TVPbkFieldTypeSelector aType )
    {
    for( TInt i = 0; i < KFieldMapTableLength; ++i )
        {
        if( aType == KFieldMapTable[i].iType )
            {
            return KFieldMapTable[i].iResId;
            }
        }

    return KErrNotFound;
    }

// --------------------------------------------------------------------------
//
// --------------------------------------------------------------------------
//
void FillL(RArray<TInt>& aArray, const TInt* aTable, const TInt aSize)
    {
    for (TInt i = 0; i < aSize; ++i)
        {
        if (aArray.Find(aTable[i]) == KErrNotFound)
            {
            // allows to add only once
            aArray.AppendL(aTable[i]);
            }
        }
    }

/**
 * Voip tables extracted from code to clear implementation logic.
 */
namespace VoipTables {
    const TInt KVoipEnabledFieldSelectors[] = {
                    R_VPBK_VOIP_ADDRESS_SELECTOR,
                    R_VPBK_PTT_ADDRESS_SELECTOR,
                    R_VPBK_SIP_ADDRESS_SELECTOR
                    };
    const TInt KVoipEnabledFieldSelectorsSize =
        sizeof(KVoipEnabledFieldSelectors) / sizeof(TInt);

    const TInt KVoipCallOutFieldSelectors[] = {
                    R_VPBK_VOIP_CALL_OUT_SELECTOR
                    };
    const TInt KVoipCallOutFieldSelectorsSize =
        sizeof(KVoipCallOutFieldSelectors) / sizeof(TInt);

    const TInt KVoipXspProviderSupportsVoipSelectors[] = {
            R_VPBK_IMPP_SELECTOR
            };
    const TInt KVoipXspProviderSupportsVoipSelectorsSize =
        sizeof(KVoipXspProviderSupportsVoipSelectors) / sizeof(TInt);
}

// --------------------------------------------------------------------------
//
// --------------------------------------------------------------------------
//
const CSPProperty* GetProperty(const CSPEntry& aEntry, TServicePropertyName mask)
    {
    const CSPProperty* result = NULL;
    if (aEntry.GetProperty(result, mask) == KErrNone)
        {
        return result;
        }
    return result;
    }

// --------------------------------------------------------------------------
//
// --------------------------------------------------------------------------
//
TInt GetIntValue(const CSPProperty* aProperty)
    {
    TInt value = 0;
    if (aProperty && aProperty->GetValue(value) == KErrNone)
        {
        return value;
        }
    return 0;
    }

// --------------------------------------------------------------------------
//
// --------------------------------------------------------------------------
//
void VoipSelectorsL(RArray<TInt>& aArray)
    {
    // Special Voip checker, which selectors can be included in which case
    RIdArray idArray;
    CleanupClosePushL(idArray);

    CSPSettings* settings = CSPSettings::NewLC();
    User::LeaveIfError( settings->FindServiceIdsL(idArray) );
    for (TInt i = 0; i < idArray.Count(); ++i)
        {
        CSPEntry* entry = CSPEntry::NewLC();
        TServiceId id = idArray[i];
        User::LeaveIfError( settings->FindEntryL(id, *entry) );
        // service is an xsp service
        const CSPProperty* tmpProp = GetProperty(*entry, EPropertyServiceAttributeMask);
        TInt value = GetIntValue(tmpProp);
        if (value & ESupportsInternetCall)
            {
            // supports voip
            FillL(aArray, VoipTables::KVoipEnabledFieldSelectors,
                    VoipTables::KVoipEnabledFieldSelectorsSize);
            // include xsp fields
            FillL(aArray, VoipTables::KVoipXspProviderSupportsVoipSelectors,
                    VoipTables::KVoipXspProviderSupportsVoipSelectorsSize);
            }
        CleanupStack::PopAndDestroy(); // entry
        }

    if (settings->IsFeatureSupported(ESupportCallOutFeature))
        {
        // supports call out, add call out field types
        FillL(aArray, VoipTables::KVoipCallOutFieldSelectors,
                VoipTables::KVoipCallOutFieldSelectorsSize);
        }

    CleanupStack::PopAndDestroy(2); // settings, idArray
    }

// --------------------------------------------------------------------------
//
// --------------------------------------------------------------------------
//
RArray<TInt> FilteredSelectorsL(
        VPbkFieldTypeSelectorFactory::TVPbkContactActionTypeSelector aType)
    {
    RArray<TInt> result;
    CleanupClosePushL(result);
    switch (aType)
        {
        case VPbkFieldTypeSelectorFactory::EVoiceCallSelector:
            {
            result.AppendL(R_VPBK_VOICE_CALL_ACTION_SELECTOR);
            break;
            }
        case VPbkFieldTypeSelectorFactory::EUniEditorSelector:
            {
            CVPbkLocalVariationManager* localVariation =
                CVPbkLocalVariationManager::NewL();
            CleanupStack::PushL(localVariation);
            
            if ( localVariation->LocallyVariatedFeatureEnabled(
                		EVPbkLVShowEmailInSendMsg ) )
            {
                result.AppendL(R_VPBK_UNIEDITOR_EMAIL_ACTION_SELECTOR);
            }
            else
            {
                result.AppendL(R_VPBK_UNIEDITOR_ACTION_SELECTOR);
            }
            CleanupStack::PopAndDestroy(localVariation);
            break;
            }
        case VPbkFieldTypeSelectorFactory::EEmailEditorSelector:
            {
            result.AppendL(R_VPBK_EMAIL_ADDRESS_SELECTOR);
            break;
            }
        case VPbkFieldTypeSelectorFactory::EInstantMessagingSelector:
            {
            result.AppendL(R_VPBK_IMPP_SELECTOR);
            break;
            }
        case VPbkFieldTypeSelectorFactory::EVOIPCallSelector:
            {
            VoipSelectorsL(result);
            break;
            }
        case VPbkFieldTypeSelectorFactory::EURLSelector:
            {
            result.AppendL(R_VPBK_URL_ADDRESS_SELECTOR);
            break;
            }
        case VPbkFieldTypeSelectorFactory::EVideoCallSelector:
            {
            result.AppendL(R_VPBK_VIDEO_NUMBER_SELECTOR);
            result.AppendL(R_VPBK_MOBILE_NUMBER_SELECTOR);
            break;
            }
        case VPbkFieldTypeSelectorFactory::EFindOnMapSelector:
        case VPbkFieldTypeSelectorFactory::EAssignFromMapSelector:
            {
            result.AppendL(R_VPBK_ADDRESS_SELECTOR);
            break;
            }
        }

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

// --------------------------------------------------------------------------
//
// --------------------------------------------------------------------------
//
TResourceReader CreateSelectorResourceReaderLC(TInt aResourceId, RFs& aFs)
    {
    //Read resource file
    VPbkEngUtils::RLocalizedResourceFile resFile;
    resFile.OpenLC( aFs, KVPbkRomFileDrive,
                    KDC_RESOURCE_FILES_DIR,
                    KVPbkFieldTypeSelectorsResFileName );
    TResourceReader resReader;
    HBufC8* selectorBuf = resFile.AllocReadLC( aResourceId );
    resReader.SetBuffer( selectorBuf );
    CleanupStack::Pop(); // selectorBuf
    CleanupStack::PopAndDestroy(); // resFile
    CleanupStack::PushL(selectorBuf);
    return resReader;
    }

/**
 * Appends a filter for the given field iType selector.
 *
 * @param aRessourceId Selector ressource Id.
 * @param aFieldTypeList Field iType list used to search
 *                       for the field.
 * @return A new instance of CVPbkFieldTypeSelector
 */
CVPbkFieldTypeSelector* CreateSelectorL(
                TInt aRessourceId, RFs& aFs, const MVPbkFieldTypeList& aFieldTypeList )
    {
    TResourceReader resourceReader = CreateSelectorResourceReaderLC(aRessourceId, aFs);

    //create and return CVPbkFieldTypeSelector
    CVPbkFieldTypeSelector* returnPtr =  CVPbkFieldTypeSelector::NewL(
            resourceReader, aFieldTypeList );

    //Cleanup
    CleanupStack::PopAndDestroy(); // resourReader

    return returnPtr;
    }

} // namespace

// --------------------------------------------------------------------------
// VPbkFieldTypeSelectorFactory::BuildFieldTypeSelectorL
// --------------------------------------------------------------------------
//
EXPORT_C CVPbkFieldTypeSelector*
                VPbkFieldTypeSelectorFactory::BuildFieldTypeSelectorL(
                TVPbkFieldTypeSelector aType,
                const MVPbkFieldTypeList& aFieldTypeList)
    {
    //Connect fileserver
    RFs fSrv;
    User::LeaveIfError( fSrv.Connect() );
    CleanupClosePushL( fSrv );

    //Map iType to resource
    TInt resourceId = MapFieldTypeSelectorToRessourceId( aType );

    // leave if no appropriate resource id has not been found
    User::LeaveIfError(resourceId);
    CVPbkFieldTypeSelector* result = CreateSelectorL( resourceId, fSrv, aFieldTypeList );
    CleanupStack::PopAndDestroy(); // fSrv
    return result;
    }

// --------------------------------------------------------------------------
// VPbkFieldTypeSelectorFactory::BuildContactActionTypeSelectorL
// --------------------------------------------------------------------------
//
EXPORT_C CVPbkFieldTypeSelector*
                VPbkFieldTypeSelectorFactory::BuildContactActionTypeSelectorL(
                TVPbkContactActionTypeSelector aType,
                const MVPbkFieldTypeList& aFieldTypeList )
    {
    //Connect fileserver
    RFs fSrv;
    User::LeaveIfError( fSrv.Connect() );
    CleanupClosePushL( fSrv );

    RArray<TInt> fieldTypeSelectors = FilteredSelectorsL(aType);
    CleanupClosePushL(fieldTypeSelectors);

    CVPbkFieldTypeSelector* result = CVPbkFieldTypeSelector::NewL(aFieldTypeList);
    CleanupStack::PushL(result);
    result->SetContactActionType(aType);
    for (TInt i = 0; i < fieldTypeSelectors.Count(); ++i)
        {
        TInt resourceId = fieldTypeSelectors[i];
        if (resourceId != KErrNotFound)
            {
            TResourceReader reader = CreateSelectorResourceReaderLC(resourceId, fSrv);
            result->AppendL(reader);
            CleanupStack::PopAndDestroy(); // reader
            }
        }

    CleanupStack::Pop(); // result
    CleanupStack::PopAndDestroy(2); // fieldTypeSelectors, fSrv
    return result;
    }

// --------------------------------------------------------------------------
// VPbkFieldTypeSelectorFactory::CreateActionTypeSelectorIdL
// --------------------------------------------------------------------------
//
EXPORT_C VPbkFieldTypeSelectorFactory::TVPbkContactActionTypeSelector
       VPbkFieldTypeSelectorFactory::CreateActionTypeSelectorIdL( const TInt aID )
    {
    if(
        aID == VPbkFieldTypeSelectorFactory::EEmptySelector ||
        aID == VPbkFieldTypeSelectorFactory::EVoiceCallSelector ||
        aID == VPbkFieldTypeSelectorFactory::EUniEditorSelector ||
        aID == VPbkFieldTypeSelectorFactory::EEmailEditorSelector ||
        aID == VPbkFieldTypeSelectorFactory::EInstantMessagingSelector ||
        aID == VPbkFieldTypeSelectorFactory::EVOIPCallSelector ||
        aID == VPbkFieldTypeSelectorFactory::EURLSelector ||
        aID == VPbkFieldTypeSelectorFactory::EVideoCallSelector ||
        aID == VPbkFieldTypeSelectorFactory::EFindOnMapSelector ||
        aID == VPbkFieldTypeSelectorFactory::EAssignFromMapSelector ||
        aID == VPbkFieldTypeSelectorFactory::EPocSelector
       )
        {
        return (VPbkFieldTypeSelectorFactory::TVPbkContactActionTypeSelector)aID;
        }
    else
        {
        User::Leave( KErrNotFound );

        // sloc - Stupid Line Of Code : but compiler expects
        return VPbkFieldTypeSelectorFactory::EPocSelector;
        }
    }

// End of file
