mpxplugins/serviceplugins/collectionplugins/mpxsqlitedbhgplugin/src/mpxdbplugin.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Wed, 13 Oct 2010 14:28:40 +0300
branchRCL_3
changeset 66 1f1dad4af8f8
parent 53 3de6c4cf6b67
permissions -rw-r--r--
Revision: 201039 Kit: 201041

/*
* Copyright (c) 2006 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 collection DB Plugin interface
*
*/


// INCLUDE FILES
#include <e32cmn.h>
#include <StringLoader.h>
#include <bautils.h>
#include <data_caging_path_literals.hrh>

#include <mpxcmn.h>
#include <mpxuser.h>
#include <mpxcollectionpluginobserver.h>
#include <mpxmediacontainerdefs.h>
#include <mpxmediamusicdefs.h>
#include <mpxmediaaudiodefs.h>
#include <mpxmediacollectiondetaildefs.h>
#include <mpxcommandgeneraldefs.h>
#include <mpxmessagegeneraldefs.h>
#include <mpxmessagecontainerdefs.h>
#include <mpxcollectioncommanddefs.h>
#include <mpxcollectionmessagedefs.h>
#include <mpxincrementalopendefs.h>
#include <mpxcollectionopenlresultdef.h>
#include <mpxmedia.h>
#include <mpxmediaarray.h>
#include <mpxdrmmediautility.h>
#include <mpxmediadrmdefs.h>
#include <mpxlog.h>
#include <mpxcollectiondbhgres.rsg>
#include <mpxdbhgplugin.mbg>
#include <centralrepository.h>

#ifdef RD_MULTIPLE_DRIVE
#include <driveinfo.h>
#endif //RD_MULTIPLE_DRIVE

#include "mpxresource.h"
#include "mpxdbcommondef.h"
#include "mpxdbcommonutil.h"

#include "mpxdbhandler.h"
#include "mpxdbutil.h"
#include "mpxcollectiondbdef.h"
#include "mpxdbplugin.h"

// CONSTANTS
_LIT(KMPlayerDbPluginMbmFile, "mpxdbhgplugin.mif");
const TInt KFirstFetchCount = 400;

const TUid KCRUIDMusicPlayerFeatures = { 0x101FFCD0 };
const TInt KMusicPlayerFeatures = 1;
const TInt KDisablePodcasting = 0x08;

const TInt KIncrementalDeleteCount = 400;

const TInt KSQLErrGeneral = -311; // SQL General error. Don't want to include sql header here
// ============================ MEMBER FUNCTIONS ==============================

// ----------------------------------------------------------------------------
// Two-phased constructor.
// ----------------------------------------------------------------------------
//
CMPXDbPlugin* CMPXDbPlugin::NewL(
    TAny* /*aInitParams*/)
    {
    MPX_FUNC("CMPXDbPlugin::NewL");

    CMPXDbPlugin* self = new (ELeave) CMPXDbPlugin();
    CleanupStack::PushL (self);
    self->ConstructL ();
    CleanupStack::Pop (self);
    return self;
    }

// ----------------------------------------------------------------------------
// Destructor.
// ----------------------------------------------------------------------------
//
CMPXDbPlugin::~CMPXDbPlugin()
    {
    MPX_FUNC("CMPXDbPlugin::~CMPXDbPlugin");

    iSelections.Reset();
    iSelections.Close();
    iFs.Close();
    delete iDbHandler;
    delete iDrmMediaUtility;
    if (iResource)
        {
        iResource->Release();
        }
    iMusicLibraryMenuIds.Close();
    delete iMusicLibraryMenuTitles;
    delete iMusicLibraryTitles;
    delete iAllSongsForArtistTitle;
    delete iMusicMenuTitle;

    if (iActiveTask)
        {
        iActiveTask->Cancel();
        delete iActiveTask;
        }
    }

// ----------------------------------------------------------------------------
// Constructor.
// ----------------------------------------------------------------------------
//
CMPXDbPlugin::CMPXDbPlugin()
    {
    MPX_FUNC("CMPXDbPlugin::CMPXDbPlugin");
    }

// ----------------------------------------------------------------------------
// Symbian 2nd phase constructor can leave.
// ----------------------------------------------------------------------------
//
void CMPXDbPlugin::ConstructL()
    {
    MPX_FUNC("CMPXDbPlugin::ConstructL");
    iFirstDeleteStep = ETrue;
    User::LeaveIfError(iFs.Connect());
    iDrmMediaUtility = CMPXDrmMediaUtility::NewL();

    TParse parse;
    parse.Set( KMPXCollectionDbResourceFile, &KDC_APP_RESOURCE_DIR, NULL );
    TFileName resFile(parse.FullName());
    User::LeaveIfError(MPXUser::CompleteWithDllPath(resFile));
    BaflUtils::NearestLanguageFile(iFs, resFile);
    iResource = CMPXResource::NewL(resFile);

    iDbHandler = CMPXDbHandler::NewL(iFs, *iResource);
    iMusicLibraryMenuTitles = iResource->ReadMenuArrayL(R_MC_MENU_ITEMS_ARRAY, iMusicLibraryMenuIds);
    iMusicLibraryTitles = iResource->ReadMenuArrayL(R_MC_TITLE_ITEMS_ARRAY, iMusicLibraryMenuIds );
    iAllSongsForArtistTitle = iResource->ReadHBufCL(R_MC_ALL_SONGS_FOR_ARTIST);

#ifdef __ENABLE_MUSIC_TEXT_ALIGNMENT
    iMusicMenuTitle = iResource->ReadHBufCL(R_MPX_QTN_MP_TITLE_MY_MUSIC_MENU_NSERIES);
#else
    iMusicMenuTitle = iResource->ReadHBufCL(R_MPX_QTN_MUS_TITLE_MUSIC_MENU);
#endif // __ENABLE_MUSIC_TEXT_ALIGNMENT


    iActiveTask = CMPXDbActiveTask::NewL(*this);

    CRepository* cenrep(NULL);
    TRAPD( err, cenrep = CRepository::NewL( KCRUIDMusicPlayerFeatures ) );
    if( err == KErrNone )
        {
        TInt val(0);
        cenrep->Get( KMusicPlayerFeatures, val );
        iDisablePodcasting = val&KDisablePodcasting ? ETrue:EFalse;
        delete cenrep;
        }
    else
        {
        iDisablePodcasting = EFalse;
        }
    iAllSongsValid = ETrue;
    }

// ----------------------------------------------------------------------------
// Navigates to the given path
// ----------------------------------------------------------------------------
//
void CMPXDbPlugin::OpenL(
    const CMPXCollectionPath& aPath,
    const TArray<TMPXAttribute>& /*aAttrs*/,
    CMPXFilter* aFilter)
    {
    MPX_FUNC("CMPXDbPlugin::OpenL");
    MPX_DEBUG_PATH(aPath);
    //Create a path object to be returned.
    CMPXCollectionPath* path = CMPXCollectionPath::NewL(aPath);
    CleanupStack::PushL(path);
    RArray<TMPXAttribute> openAttrs;
    CleanupClosePushL(openAttrs);

    RArray<TInt> supportedIds;
    CleanupClosePushL(supportedIds);

    // Replace the attributes requested by the client with the ones below.
    // This will eventually have to be fixed
    SetAttributesL(aPath, openAttrs, supportedIds);

    CMPXMedia* entries = CMPXMedia::NewL(supportedIds.Array());
    CleanupStack::PopAndDestroy(&supportedIds);
    CleanupStack::PushL(entries);
    //Add returned path into media
    entries->SetTObjectValueL<TInt>(KMPXMediaGeneralValue, (TInt)path);

    TInt error(KErrNone);
    TBool isASong(EFalse);
    CMPXCollectionPath* newPath(NULL);

    // Make sure we handle open the correct open mode
    //
    TMPXOpenMode openmode = aPath.OpenNextMode();
    switch (openmode)
        {
        case EMPXOpenGroupOrPlaylist:
            {
            // Open By Path
            MPX_TRAP(error, isASong = DoOpenL(aPath, openAttrs.Array(), *entries, aFilter));
            break;
            }

        case EMPXOpenPlaylistOnly:
            {
            if (aPath.Count() > 0)
                {
                // Try to open
                MPX_TRAP(error, newPath = DoOpenPlaylistL(aPath, openAttrs.Array()));
                CleanupStack::PushL(newPath);
                isASong = ETrue;
                }
            else // no items
                {
                MPX_TRAP(error, isASong = DoOpenL(aPath, openAttrs.Array(), *entries, aFilter));
                }

            break;
            }

        default:
            // do nothing
            break;
        }

    // generate the callback
    if (isASong )
        {
        if (openmode == EMPXOpenGroupOrPlaylist)
            {
            iObs->HandleOpen(const_cast<CMPXCollectionPath*>(&aPath), error);
            }
        else  // openmode == EMPXOpenPlaylistOnly
            {
            iObs->HandleOpen(newPath, error);
            }
        }
    else
        {
        entries->SetCObjectValueL(KMPXMediaGeneralContainerPath,
            const_cast<CMPXCollectionPath*>(&aPath));
        entries->Delete(KMPXMediaGeneralValue);
        iObs->HandleOpen(entries, path, error);
        }

    if (newPath)
        {
        CleanupStack::PopAndDestroy(newPath);
        }

    CleanupStack::PopAndDestroy(entries);
    CleanupStack::PopAndDestroy(&openAttrs);
    CleanupStack::PopAndDestroy(path);
    }

// ----------------------------------------------------------------------------
// Get the extended properties of the current file (async)
// ----------------------------------------------------------------------------
//
void CMPXDbPlugin::MediaL(
    const CMPXCollectionPath& aPath,
    const TArray<TMPXAttribute>& aAttrs,
    const TArray<TCapability>& /*aCaps*/,
    CMPXAttributeSpecs* /*aSpecs*/)
    {
    MPX_FUNC("CMPXDbPlugin::MediaL");
    MPX_DEBUG_PATH(aPath);

    RArray<TInt> supportedIds;
    CleanupClosePushL(supportedIds);
    if (aPath.Selection().Count())
        {
        // it's a container if there are multiple selection, else it's not a container
        supportedIds.AppendL(KMPXMediaIdContainer);
        }
    MPXDbCommonUtil::FillInSupportedUIDsL(aAttrs, supportedIds);

    CMPXMedia* entries = CMPXMedia::NewL(supportedIds.Array());
    CleanupStack::PopAndDestroy(&supportedIds);
    CleanupStack::PushL(entries);

    DoMediaL(aPath, aAttrs, *entries);

    // Also fetch collection details and set the path if required
    DoHandleOtherMediaAttributesL(aAttrs, aPath, *entries);

    iObs->HandleMedia(entries, KErrNone);
    CleanupStack::PopAndDestroy(entries);
    }

// ----------------------------------------------------------------------------
// Cancel outstanding request
// ----------------------------------------------------------------------------
//
void CMPXDbPlugin::CancelRequest()
    {
    MPX_FUNC("CMPXDbPlugin::CancelRequest");
    iActiveTask->Cancel();
    }

// ----------------------------------------------------------------------------
// Executes the given command on the collection
// ----------------------------------------------------------------------------
//
void CMPXDbPlugin::CommandL(
    TMPXCollectionCommand aCmd,
    TInt aArg /* = 0 */)
    {
    MPX_FUNC("CMPXDbPlugin::CommandL");
    MPX_DEBUG2("CMPXDbPlugin::CommandL %d", aCmd);
    iAllSongsValid = ETrue;
    switch (aCmd)
        {
        case EMcCmdRemoveAll:
            {
            MPX_DEBUG1("CMPXDbPlugin::CommandL - EMcCmdRemoveAll");
            // Remove EVERYthing from the collection
            iDbHandler->RemoveEntireCollectionL();
            break;
            }
        case EMcCmdClose:
        	  // called before destructing this plug-in: no actions required
        	  break;
        case EMcCloseCollection:
            {
            MPX_DEBUG2("CMPXDbPlugin::CommandL - EMcCloseCollection %d", aArg);
            // Close the specified database
            TRAP_IGNORE(iDbHandler->PreCloseCollectionL());
 #ifdef RD_MULTIPLE_DRIVE
            MPX_DEBUG1("Multiple drives closing databases");
            if ( aArg <0)
                {
                DriveInfo::TDriveArray driveArray;
                User::LeaveIfError ( DriveInfo::GetUserVisibleDrives( iFs, driveArray));
                TInt count( driveArray.Count ());
                for (TInt i=0; i<count; ++i)
                    {
                    MPX_DEBUG2("At drive %i", driveArray[i]);
                    if (( driveArray[i] != EDriveC) && (!iDbHandler->IsRemoteDrive(static_cast<TDriveNumber>(driveArray[i]))))
                        {
                        MPX_DEBUG2("Closing database %i", driveArray[i]);
                        TRAP_IGNORE( iDbHandler->CloseDatabaseL( driveArray[i] ) );
                        }
                    }
                }
            else
                {
                TRAP_IGNORE( iDbHandler->CloseDatabaseL(aArg) ); //Closing can fail if physical media has been removed or forced disk dismount has occurred.
                }
 #else
            iDbHandler->CloseDatabaseL(aArg);
 #endif // RD_MULTIPLE_DRIVE
            break;
            }
        case EMcReOpenCollection:
            {
            MPX_DEBUG1("CMPXDbPlugin::CommandL - EMcReOpenCollection");
            // Open the specified database
#ifdef RD_MULTIPLE_DRIVE
            MPX_DEBUG1("Multiple drives opening databases");
            DriveInfo::TDriveArray driveArray;
            User::LeaveIfError( DriveInfo::GetUserVisibleDrives( iFs, driveArray ) );
            TInt count( driveArray.Count() );
            for( TInt i=0; i<count; ++i )
                {
                MPX_DEBUG2("At drive %i", driveArray[i]);
                if( (driveArray[i] != EDriveC)  && (!iDbHandler->IsRemoteDrive(static_cast<TDriveNumber>(driveArray[i]))))
                    {
                    TUint driveStatus(0);
                    User::LeaveIfError( DriveInfo::GetDriveStatus(
                        iFs, driveArray[i], driveStatus ) );
                    if( driveStatus & DriveInfo::EDrivePresent )
                        {
                        MPX_DEBUG2("Opening database %i", driveArray[i]);
                        TRAP_IGNORE( iDbHandler->OpenDatabaseL( driveArray[i] ) );
                        }
                    }
                }
#else
            iDbHandler->OpenDatabaseL(aArg);
#endif // RD_MULTIPLE_DRIVE
            break;
            }
        case EMcRefreshStarted:
            {
            MPX_DEBUG1("CMPXDbPlugin::CommandL - EMcRefreshStarted");
            iDbHandler->CheckDiskSpaceOnDrivesL();
            // ask the handler to start a transaction
            iDbHandler->RefreshStartL();
            iRefreshing=ETrue;
            break;
            }
        case EMcRefreshEnded:
            {
            MPX_DEBUG1("CMPXDbPlugin::CommandL - EMcRefreshEnded");
            // ask the handler to finalize the transaction
            iDbHandler->RefreshEndL();
            iRefreshing=EFalse;
            break;
            }
         case EMcCmdReCreateDB:
            {
            MPX_DEBUG1("CMPXDbPlugin::CommandL - EMcCmdReCreateDB");
            // Recreate all databases
            iDbHandler->ReCreateDatabasesL();
            break;
            }
         case EMcCmdDbCorrupted:
            {
            MPX_DEBUG1("CMPXDbPlugin::CommandL - EMcCmdDbCorrupted");
            iDbHandler->SetDBCorruptedL(ETrue);
            break;
            }
        case EMcCmdRefresh:
        case EMcCmdCollectionInit:
        case EMcCmdCollectionResyn:
            {
            // deprecated
            break;
            }
        case EMcCmdMtpStart:
            iDbHandler->CheckDiskSpaceOnDrivesL();
            iMtpInUse = ETrue;
            iDbHandler->MtpStartL();
            break;
        case EMcCmdMtpEnd:
            iMtpInUse = EFalse;
            iDbHandler->MtpEndL();
            break;
         default:
            {
            User::Leave(KErrNotSupported);
            }
        }
    }

// ----------------------------------------------------------------------------
// Executes the given command on the collection
// ----------------------------------------------------------------------------
//
void CMPXDbPlugin::CommandL(
    CMPXCommand& aCmd)
    {
    MPX_FUNC("CMPXDbPlugin::CommandL");

    if (!aCmd.IsSupported(KMPXCommandGeneralId))
        {
        User::Leave(KErrArgument);
        }

    TMPXCommandId commandId = aCmd.ValueTObjectL<TMPXCommandId>(KMPXCommandGeneralId);

    TBool syncOp(EFalse);
    if (aCmd.IsSupported(KMPXCommandGeneralDoSync))
        {
        syncOp = aCmd.ValueTObjectL<TBool>(KMPXCommandGeneralDoSync);
        }

    // Handle this operation synchronously or asynchronously
    //
    if (!syncOp)
        {
        iActiveTask->StartL(commandId, aCmd);
        }
    else  // Sync operation
        {
        switch (commandId)
            {
            case KMPXCommandIdCollectionRetrieveUriForDeletion:
                {
                MPX_DEBUG1("CMPXDbPlugin::CommandL - KMPXCommandIdCollectionRetrieveUriForDeletion");
                DoRetrieveUriForDeletionL(aCmd);
                break;
                }
            case KMPXCommandIdCollectionRemove:
                {
                MPX_DEBUG1("CMPXDbPlugin::CommandL - KMPXCommandIdCollectionRemove");
                if ( !iDbHandler->InTransaction() )
                    {
                    iDbHandler->BeginTransactionL();
                    }

                if (iFirstDeleteStep )
                    {
                    iFirstDeleteStep = EFalse;
                    }
                DoRemovePathL(aCmd);
                break;
                }
            case KMPXCommandIdCollectionRemoveMedia:
                {
                MPX_DEBUG1("CMPXDbPlugin::CommandL - KMPXCommandIdCollectionRemoveMedia");
                DoRemoveMediaL(aCmd);
                break;
                }
            case KMPXCommandIdCollectionCleanupDeletedMedias:
                {
                MPX_DEBUG1("CMPXDbPlugin::CommandL - KMPXCommandIdCollectionCleanupDeletedMedias");
                CleanupDeletedRecordsL(aCmd);
                break;
                }
            case KMPXCommandIdCollectionAdd:
                {
                MPX_DEBUG1("CMPXDbPlugin::CommandL - KMPXCommandIdCollectioAdd");
                CMPXMedia* media = aCmd.Value<CMPXMedia>(KMPXCommandColAddMedia);
                User::LeaveIfNull( media );
                TUint32 id(DoAddL(*media));
                aCmd.SetTObjectValueL<TMPXItemId>(KMPXCommandColAddRtnId, id);
                break;
                }
            case KMPXCommandIdCollectionSet:
                {
                MPX_DEBUG1("CMPXDbPlugin::CommandL - KMPXCommandIdCollectionSet");
                CMPXMedia* media = aCmd.Value<CMPXMedia>(KMPXCommandColSetMedia);
                User::LeaveIfNull( media );
                DoSetL(*media);
                break;
                }
            case KMPXCommandIdCollectionCompleteDelete:
                {
                MPX_DEBUG1("CMPXDbPlugin::CommandL - KMPXCommandIdCollectionCompleteDelete");
                DoHandleDeleteCompleteL(aCmd);
                break;
                }
            case KMPXCommandIdReorderPlaylist:
                {
                MPX_DEBUG1("CMPXDbPlugin::CommandL - KMPXCommandIdReorderPlaylist");
                DoReorderPlaylistL(aCmd);
                break;
                }
            case KMPXCommandIdUpdateRefreshTime:
                {
                MPX_DEBUG1("CMPXDbPlugin::CommandL - KMPXCommandIdUpdateRefreshTime");
                TTime curTime;
                curTime.HomeTime();
                iDbHandler->SetLastRefreshedTimeL(curTime);
                break;
                }
            case KMPXCommandCollectionGetCount:
                {
                MPX_DEBUG1("CMPXDbPlugin::CommandL - KMPXCommandCollectionGetCount");
                DoGetCollectionCountL(aCmd);
                break;
                }
            case KMPXCommandCollectionGetURIs:
                {
                MPX_DEBUG1("CMPXDbPlugin::CommandL - KMPXCommandCollectionGetURIs");
                DoGetCollectionUriL(aCmd);
                break;
                }
            default:
                {
                User::Leave(KErrNotSupported);
                }
            }
        }
    }

// ----------------------------------------------------------------------------
// Adds an item (song or playlist) to the collection
// ----------------------------------------------------------------------------
//
void CMPXDbPlugin::AddL(
    const CMPXMedia& aMedia)
    {
    MPX_FUNC("CMPXDbPlugin::AddL");
    DoAddL(aMedia);
    }

// ----------------------------------------------------------------------------
// Remove an item from the collection database using the given path
// ----------------------------------------------------------------------------
//
void CMPXDbPlugin::RemoveL(
    const CMPXCollectionPath& aPath)
    {
    MPX_FUNC("CMPXDbPlugin::RemoveL(by path)");
    MPX_DEBUG_PATH(aPath);

    CMPXMessageArray* msgAry = CMPXMessageArray::NewL();
    CleanupStack::PushL(msgAry);

    // Return file path for deleted item(s)
    CDesCArray* fp = DoRemoveL(aPath, *msgAry);

    iObs->HandleRemove(*fp, KErrNone);
    delete fp;

    // Send Change Messages
    iActiveTask->SetVisibleChange(CMPXDbActiveTask::EAllVisible);
    DoHandleChangeL(msgAry);
    CleanupStack::PopAndDestroy(msgAry);
    }

// ----------------------------------------------------------------------------
// Remove an item from the collection database using the given media properties
// ----------------------------------------------------------------------------
//
void CMPXDbPlugin::RemoveL(
    const CMPXMedia& aMedia)
    {
    MPX_FUNC("CMPXDbPlugin::RemoveL(by media)");
    DoRemoveL(aMedia, EFalse);
    }

// ----------------------------------------------------------------------------
// Sets/updates the media for an item in the collection
// DEPRECATED for week 18
// ----------------------------------------------------------------------------
//
void CMPXDbPlugin::SetL(
    const CMPXMedia& aMedia)
    {
    MPX_FUNC("CMPXDbPlugin::SetL");
    DoSetL(aMedia);
    }

// ----------------------------------------------------------------------------
// Find the items matching the media specifications
// ----------------------------------------------------------------------------
//
void CMPXDbPlugin::FindAllL(
    const CMPXMedia& aCriteria,
    const TArray<TMPXAttribute>& aAttrs)
    {
    MPX_FUNC("CMPXDbPlugin::FindAllL");

    CMPXMedia* entries = FindAllSyncL(aCriteria, aAttrs);

    // notify client. if FindAllL leaves, framework will notify client of the error
    iObs->HandleFindAll(entries, KErrNone);
    delete entries;
    }

// ----------------------------------------------------------------------------
// Find the items matching the media specifications
// ----------------------------------------------------------------------------
//
CMPXMedia* CMPXDbPlugin::FindAllSyncL(
    const CMPXMedia& aCriteria,
    const TArray<TMPXAttribute>& aAttrs)
    {
    MPX_FUNC("CMPXDbPlugin::FindAllSyncL");

    CMPXMedia* entries = iDbHandler->FindAllLC(aCriteria, aAttrs);

    if (entries)
        {
        CMPXMediaArray* ary = entries->Value<CMPXMediaArray>(KMPXMediaArrayContents);
        User::LeaveIfNull( ary );
        DoSetDrmForArrayL( *ary, aAttrs );
        }

    CleanupStack::Pop(entries);
    return entries;
    }

// ----------------------------------------------------------------------------
// Get the list of supported capabilities
// ----------------------------------------------------------------------------
//
TCollectionCapability CMPXDbPlugin::GetCapabilities()
    {
    // This one supports simple search
    return EMcSearch;
    }

// ----------------------------------------------------------------------------
// Get the list of supported capabilities
// ----------------------------------------------------------------------------
//
TBool CMPXDbPlugin::HandleStepL()
    {
    MPX_FUNC("CMPXDbPlugin::HandleStepL");

    TBool done(ETrue);

    switch (iActiveTask->GetTask())
        {
        case KMPXCommandIdCollectionSet:
            {
            done = DoSetAsyncL();
            break;
            }
        case KMPXCommandIdCollectionAdd:
            {
            done = DoAddAsyncL();
            break;
            }
        case KMPXCommandIdCollectionRemove:
            {
            DoRemovePathL(iActiveTask->GetCommand());
            done = ETrue;
            break;
            }
        case KMPXCommandIdCollectionRemoveMedia:
            {
            DoRemoveMediaL(iActiveTask->GetCommand());
            done = ETrue;
            break;
            }
        case KMPXCommandIdCollectionRetrieveUriForDeletion:
            {
            DoRetrieveUriForDeletionL(iActiveTask->GetCommand());
            done = ETrue;
            break;
            }
        case KMPXCommandIdCollectionCleanupDeletedMedias:
            {
            CleanupDeletedRecordsL(iActiveTask->GetCommand());
            done = ETrue;
            break;
            }
        case KMPXCommandIdCollectionCompleteDelete:
            {
            DoHandleDeleteCompleteL( iActiveTask->GetCommand() );
            break;
            }
        case KMPXCommandIdUpdateRefreshTime:
            {
            MPX_DEBUG1("CMPXDbPlugin::CommandL - KMPXCommandIdUpdateRefreshTime");
            TTime curTime;
            curTime.HomeTime();
            iDbHandler->SetLastRefreshedTimeL(curTime);
            break;
            }
        case KMPXCommandIdIncrementalOpenL:
            {
            DoIncrementalOpenL( iActiveTask->GetCommand() );
            done = ETrue;
            break;
            }
        default:
            {
            // Should never happen!
            ASSERT(0);
            break;
            }
        }
    return done;
    }

// ----------------------------------------------------------------------------
// Handler for async operations completed
// ----------------------------------------------------------------------------
//
void CMPXDbPlugin::HandleOperationCompleted(
    TInt aErr)
    {
    MPX_FUNC("CMPXDbPlugin::HandleOperationCompleted");
    TRAP_IGNORE(DoHandleOperationCompletedL(aErr));
    }

// ----------------------------------------------------------------------------
// Process the OpenL command
// ----------------------------------------------------------------------------
//
TBool CMPXDbPlugin::DoOpenL(
    const CMPXCollectionPath& aPath,
    const TArray<TMPXAttribute>& aAttrs,
    CMPXMedia& aEntries,
    CMPXFilter* aFilter )
    {
    MPX_FUNC("CMPXDbPlugin::DoOpenL");

    TInt err( KErrNone );
    CMPXMediaArray* array = CMPXMediaArray::NewL();
    CleanupStack::PushL(array);

    TInt levels(aPath.Levels());
    TBool isASong(EFalse);


	if ( 1 == levels )
	    {

	    // Redirecting all open requests at level 1 to open albums 
	    // due to UI changes that removed the library menu collection level.
        TInt acount = array->Count();
        MPX_DEBUG2(" array count11 [%d]", acount);
        
 		CMPXCollectionPath* path = CMPXCollectionPath::NewL(aPath);
		CleanupStack::PushL( path );
		
		path->AppendL(3); // Albums
		TInt whatLevel = path->Levels();

		MPX_DEBUG_PATH(*path);
		
		aEntries.SetTObjectValueL<TMPXItemId>(KMPXMediaGeneralId, path->Id(whatLevel - 1) );
		
      // Create a media which hold the pointer to the returned path
        if (aEntries.IsSupported(KMPXMediaGeneralValue))
            {
            MPX_DEBUG1(" pointer to the returned path ");
            CMPXMedia* pMedia = CMPXMedia::NewL();
            CleanupStack::PushL(pMedia);
            pMedia->SetTObjectValueL<TInt>(KMPXMediaGeneralValue,
                                          aEntries.ValueTObjectL<TInt>(KMPXMediaGeneralValue));
            array->AppendL(*pMedia);
            CleanupStack::PopAndDestroy(pMedia);
            }
		
	
        RArray<TMPXAttribute> openAttrs;
        CleanupClosePushL(openAttrs);

        RArray<TInt> supportedIds;
        CleanupClosePushL(supportedIds);

        SetAttributesL(*path, openAttrs, supportedIds);
        openAttrs.AppendL(KMPXMediaArrayContents);
        
        CleanupStack::PopAndDestroy(&supportedIds);
		
		if( iAllSongsValid )
		    {
		    isASong = DoOpenBrowseAlbumL( *path, openAttrs.Array(), aEntries, array );
		    }
		CleanupStack::PopAndDestroy(&openAttrs);
		CleanupStack::PopAndDestroy( path );

        //Remove the first media
        if ( array->Count() &&
            (*array)[0]->IsSupported(KMPXMediaGeneralValue))
            {
            array->Remove(0);
            }
	    }
    else if (levels >= 2)
        {
	    aEntries.SetTObjectValueL<TMPXItemId>(KMPXMediaGeneralId, aPath.Id(levels - 1));
        // Create a media which hold the pointer to the returned path
        if (aEntries.IsSupported(KMPXMediaGeneralValue))
            {
            CMPXMedia* pMedia = CMPXMedia::NewL();
            CleanupStack::PushL(pMedia);
            pMedia->SetTObjectValueL<TInt>(KMPXMediaGeneralValue,
                                          aEntries.ValueTObjectL<TInt>(KMPXMediaGeneralValue));
            array->AppendL(*pMedia);
            CleanupStack::PopAndDestroy(pMedia);
            MPX_ASSERT(array->Count()==1);
            }

        // check the browse type
        switch (aPath.Id(1).iId2)
            {
            case EBrowseAll:
                {
                TBool doIncremental(ETrue);
                if( aFilter && aFilter->IsSupported( KMPXCollectionOpenLSupportsIncremental ) )
                    {
                    doIncremental =
                         aFilter->ValueTObjectL<TBool>(KMPXCollectionOpenLSupportsIncremental);
                    }

                if( doIncremental )
                    {
                    TRAP( err, isASong = DoOpenIncrementalL( aPath, aAttrs, aEntries, array ) );
                    }
                else
                    {
                    TRAP( err, isASong = DoOpenBrowseAllL(aPath, aAttrs, aEntries, array) );
                    }
                break;
                }

            case EBrowseArtist:
                {
                if( iAllSongsValid )
                    {
                    isASong = DoOpenBrowseArtistL( aPath, aAttrs, aEntries, array );
                    }
                break;
                }

            case EBrowseAlbum:
                {
                if( iAllSongsValid )
                    {
                    isASong = DoOpenBrowseAlbumL( aPath, aAttrs, aEntries, array );
                    }
                break;
                }

            case EBrowsePlaylist:
                {
                if( iAllSongsValid )
                    {
                    isASong = DoOpenBrowsePlaylistL(aPath, aAttrs, aEntries, array);
                    }

                break;
                }

            case EBrowseGenre:
                {
                if( iAllSongsValid )
                    {
                    isASong = DoOpenBrowseGenreL( aPath, aAttrs, aEntries, array );
                    }
                break;
                }

            case EBrowseComposer:
                {
                if( iAllSongsValid )
                    {
                    isASong = DoOpenBrowseComposerL( aPath, aAttrs, aEntries, array );
                    }
                break;
                }

            default:
                {
                User::Leave(KErrArgument);
                }
            }
        //Remove the first media
        if ( array->Count() &&
            (*array)[0]->IsSupported(KMPXMediaGeneralValue))
            {
            array->Remove(0);
            }
        }
    else
        {
        User::Leave(KErrNotSupported);
        }
    aEntries.SetCObjectValueL(KMPXMediaArrayContents, array);
    aEntries.SetTObjectValueL<TInt>(KMPXMediaArrayCount, array->Count());

    CleanupStack::PopAndDestroy(array);

    if( err == KSQLErrGeneral )
        {
        iAllSongsValid = EFalse;
        User::Leave( KErrDiskFull );
        }
    else if( err != KErrNone )
        {
        User::Leave( err );
        }
    return isASong;
    }


// ----------------------------------------------------------------------------
// CMPXDbPlugin::DoOpenIncrementalL
// ----------------------------------------------------------------------------
//
TBool CMPXDbPlugin::DoOpenIncrementalL( const CMPXCollectionPath& aPath,  const TArray<TMPXAttribute>& aAttrs,
                                       CMPXMedia& aEntries, CMPXMediaArray* aArray)
    {
    TBool isASong(EFalse);

    TInt levels(aPath.Levels());

    if( levels == 2 )
        {
        // Remove the pPath dummy from the array
        TInt pPath = aEntries.ValueTObjectL<TInt>(KMPXMediaGeneralValue);
        aArray->Remove(0);
        CMPXCollectionPath* p = (CMPXCollectionPath*) pPath;

        RArray<TMPXItemId> ids;
        CleanupClosePushL( ids );

        iDbHandler->GetAllSongsLimitedL( aAttrs, *aArray, KFirstFetchCount );

        TInt c( aArray->Count() );
        for( TInt i=0; i<c; ++i )
            {
            TMPXItemId id = aArray->AtL(i)->ValueTObjectL<TMPXItemId>( KMPXMediaGeneralId );
            ids.Append( id );
            }

        // Rest are all blank items
        CMPXMedia* entry = CMPXMedia::NewL();
        CleanupStack::PushL(entry);
        entry->SetTObjectValueL<TMPXGeneralType>(KMPXMediaGeneralType, EMPXItem);
        entry->SetTObjectValueL<TMPXGeneralCategory>(KMPXMediaGeneralCategory, EMPXSong);
        entry->SetTObjectValueL<TMPXItemId>(KMPXMediaGeneralId, KMPXInvalidItemId );

        TInt count = iDbHandler->NumberOfItemsL(EMPXSong);
        count-=c;
        for( TInt i=0; i<count; ++i )
            {
            aArray->AppendL( *entry );
            ids.Append( KMPXInvalidItemId );
            }
        CleanupStack::PopAndDestroy( entry );

        // Set the "Supportes incremental Command" flag
        //
        aEntries.SetTObjectValueL( KMPXCollectionOpenLSupportsIncremental, ETrue );

        TMPXOpenDataBlock block;
        block.iOffset=KErrNotFound;
        block.iSize=count;
        aEntries.SetTObjectValueL<TMPXOpenDataBlock>( KMPXCollectionOpenLResultRange, block );

        SetMediaGeneralAttributesL(aEntries, EMPXGroup, EMPXSong,
                iMusicLibraryTitles->MdcaPoint(EBrowseAll));

        p->AppendL(ids.Array());
        CleanupStack::PopAndDestroy( &ids );
        }
    else if( levels == 3 )
        {
        iDbHandler->GetSongL(aPath.Id(levels - 1).iId2, aAttrs, *aArray);
        isASong = ETrue;
        }


    return isASong;
    }

// ----------------------------------------------------------------------------
// Handles OpenL called for EBrowseAll
// ----------------------------------------------------------------------------
//
TBool CMPXDbPlugin::DoOpenBrowseAllL(
    const CMPXCollectionPath& aPath,
    const TArray<TMPXAttribute>& aAttrs,
    CMPXMedia& aEntries,
    CMPXMediaArray* aArray)
    {
    MPX_FUNC("CMPXDbPlugin::DoOpenBrowseAllL");

    TInt levels(aPath.Levels());
    switch (levels)
       {
       // All songs
       case 2:
            {
            MPX_PERF_START(CMPXDbPlugin_DoOpenBrowseAllL_All);

            iDbHandler->GetAllSongsL(aArray, aAttrs);
            SetMediaGeneralAttributesL(aEntries, EMPXGroup, EMPXSong,
                iMusicLibraryTitles->MdcaPoint(EBrowseAll));

            MPX_PERF_END(CMPXDbPlugin_DoOpenBrowseAllL_All);
            break;
            }

         // A Song in all songs
         case 3:
            {
            MPX_PERF_START(CMPXDbPlugin_DoOpenBrowseAllL_Song);

            iDbHandler->GetSongL(aPath.Id(levels - 1).iId2, aAttrs, *aArray);

            MPX_PERF_END(CMPXDbPlugin_DoOpenBrowseAllL_Song);
            break;
            }

         default:
            {
            MPX_DEBUG2("CMPXDbPlugin_DoOpenBrowseAllL: Invalid levels[%d]", levels);
            User::Leave(KErrNotSupported);
            }
        } // end switch(levels)

    return (levels == 3);
    }

// ----------------------------------------------------------------------------
// Handles OpenL called for EBrowseArtist
// ----------------------------------------------------------------------------
//
TBool CMPXDbPlugin::DoOpenBrowseArtistL(
    const CMPXCollectionPath& aPath,
    const TArray<TMPXAttribute>& aAttrs,
    CMPXMedia& aEntries,
    CMPXMediaArray* aArray)
    {
    MPX_FUNC("CMPXDbPlugin::DoOpenBrowseArtistL");

    TBool isASong(EFalse);
    TInt levels(aPath.Levels());
    TInt idIndex(levels - 1);

    RArray<TMPXItemId> selections;
    CleanupClosePushL(selections);
    aPath.SelectionL(selections);

    switch (levels)
        {
        // All artists
        case 2:
            {
            MPX_PERF_START(CMPXDbPlugin_DoOpenBrowseArtistL_All);

            iDbHandler->GetAllArtistsL(aAttrs, aArray);
            SetMediaGeneralAttributesL(aEntries, EMPXGroup, EMPXArtist,
                iMusicLibraryTitles->MdcaPoint(EBrowseArtist));

            MPX_PERF_END(CMPXDbPlugin_DoOpenBrowseArtistL_All);
            break;
            }

        // All albums of an artist
        case 3:
            {
            MPX_PERF_START(CMPXDbPlugin_DoOpenBrowseArtistL_AllAlbums);
            // get the albums
            TInt id(aPath.Id(idIndex).iId2);
            MPX_ASSERT(aArray->Count());
            MPX_ASSERT((*aArray)[0]->IsSupported(KMPXMediaGeneralValue));
            TInt pPath = (*aArray)[0]->ValueTObjectL<TInt>(KMPXMediaGeneralValue);
            MPX_ASSERT(pPath);
            iDbHandler->GetAlbumsMatchingArtistL(id, aAttrs, *aArray);
            SetMediaGeneralAttributesL(aEntries, EMPXItem, EMPXArtist, id);

            TInt count = aArray->Count();
            if ( count > 2 )
                {
                // Only show "all" item if there is more than 1 album
                // count for "all" item
                TInt total = 0;
                for ( TInt i = 1; i < count; i++ )
                {
                TInt temp = (*aArray)[i]->ValueTObjectL<TInt>(KMPXMediaGeneralCount);
                total += temp;
                }
            // Add "all" item under an artist
            MPXDbCommonUtil::PrependMediaL(*aArray, *iAllSongsForArtistTitle, EMPXItem, EMPXAlbum,
                aPath.Id(idIndex), 0, 0, 1);

                (*aArray)[1]->SetTObjectValueL<TInt>(KMPXMediaGeneralCount, total);

            TMPXItemId allId = ((*aArray)[1]->ValueTObjectL<TMPXItemId>(KMPXMediaGeneralId));
            if (aArray->Count() > 2)
                { // path media, all id  and at least one media
                ((CMPXCollectionPath*)pPath)->InsertL(allId, 0);
                }
            else
                { // only has all item
                ((CMPXCollectionPath*)pPath)->AppendL(allId);
                    }
                }

            MPX_PERF_END(CMPXDbPlugin_DoOpenBrowseArtistL_AllAlbums);
            break;
            }

        // All songs of an album for an artist or all songs for an artist
        case 4:
            {
            // all songs for an artist
            if (aPath.Id(3) == aPath.Id(2))
                {
                MPX_PERF_START(CMPXDbPlugin_DoOpenBrowseArtistL_AllSongs);

                TInt id(aPath.Id(idIndex - 1).iId2);
                iDbHandler->GetSongsMatchingArtistL(id, aAttrs, aArray);
                SetMediaGeneralAttributesL(aEntries, EMPXItem, EMPXSong, id);

                MPX_PERF_END(CMPXDbPlugin_DoOpenBrowseArtistL_AllSongs);
                }
            // all songs of an album for an artist
            else
                {
                MPX_PERF_START(CMPXDbPlugin_DoOpenBrowseArtistL_AllSongsForAlbum);
                TUint32 artistId(aPath.Id(idIndex - 1).iId2);

                if (selections.Count())
                    {
                    // Multiple albums
                    const TInt count(aPath.Selection().Count());
                    for (TInt i = 0; i < count; ++i)
                        {
                        iDbHandler->GetSongsMatchingArtistAndAlbumL(artistId, selections[i].iId2,
                            aAttrs, aArray);
                        }
                    }
                else
                    {
                    // One album
                    iDbHandler->GetSongsMatchingArtistAndAlbumL(artistId, aPath.Id(idIndex).iId2,
                        aAttrs, aArray);
                    }

                SetMediaGeneralAttributesL(aEntries, EMPXItem, EMPXAlbum, aPath.Id(idIndex).iId2);
                MPX_PERF_END(CMPXDbPlugin_DoOpenBrowseArtistL_AllSongsForAlbum);
                }

            MPX_DEBUG2("CMPXDbPlugin_DoOpenBrowseArtistL: retrieved %d items", aArray->Count());

            break;
            }

        // A Song in an album
        case 5:
            {
            MPX_PERF_START(CMPXDbPlugin_DoOpenBrowseArtistL_Song);

            iDbHandler->GetSongL(aPath.Id(idIndex).iId2, aAttrs, *aArray);
            isASong = ETrue;

            MPX_PERF_END(CMPXDbPlugin_DoOpenBrowseArtistL_Song);
            break;
            }

        default:
            {
            MPX_DEBUG2("CMPXDbPlugin_DoOpenBrowseArtistL: Invalid levels[%d]", levels);
            User::Leave(KErrNotSupported);
            }
        } // end switch(level)

    CleanupStack::PopAndDestroy(&selections);
    return isASong;
    }

// ----------------------------------------------------------------------------
// Handles OpenL called for EBrowseAlbum
// ----------------------------------------------------------------------------
//
TBool CMPXDbPlugin::DoOpenBrowseAlbumL(
    const CMPXCollectionPath& aPath,
    const TArray<TMPXAttribute>& aAttrs,
    CMPXMedia& aEntries,
    CMPXMediaArray* aArray)
    {
    MPX_FUNC("CMPXDbPlugin::DoOpenBrowseAlbumL");

    TBool isASong(EFalse);
    TInt levels(aPath.Levels());
    TInt idIndex(levels - 1);

    RArray<TMPXItemId> selections;
    CleanupClosePushL(selections);
    aPath.SelectionL(selections);

    switch (levels)
        {
        // All Albums
        case 2:
            {
            MPX_PERF_START(CMPXDbPlugin_DoOpenBrowseAlbumL_All);

            TRAPD(err, iDbHandler->GetAllAlbumsL(aAttrs, aArray) );
            // in error case, return empty list and append empty id to path 
            // in order to increase one level 
            if ( err != KErrNone )
                {
                TInt pPath(0);
                if (aArray->Count())
                    {
                    CMPXMedia* pMedia = (*aArray)[0];
                    if (pMedia->IsSupported(KMPXMediaGeneralValue))
                        {
                        pPath = pMedia->ValueTObjectL<TInt>(KMPXMediaGeneralValue);
                        MPX_ASSERT(pPath);
                        }                   
                    }

                RArray<TMPXItemId> ids;
                CleanupClosePushL(ids);
            
                // Append ids to the returned path
                if (pPath)
                    {
                    ((CMPXCollectionPath*)pPath)->AppendL(ids.Array());
                    }
                CleanupStack::PopAndDestroy(&ids);
                }
            
            SetMediaGeneralAttributesL(aEntries, EMPXGroup, EMPXAlbum,
                iMusicLibraryTitles->MdcaPoint(EBrowseAlbum));

            MPX_PERF_END(CMPXDbPlugin_DoOpenBrowseAlbumL_All);
            break;
            }

        // All songs in one or multiple albums
        case 3:
            {
            MPX_PERF_START(CMPXDbPlugin_DoOpenBrowseAlbumL_AllSongs);
            if (selections.Count())
                {
                // Multiple albums
                const TInt count(aPath.Selection().Count());
                for (TInt i = 0; i < count; ++i)
                    {
                    iDbHandler->GetSongsMatchingAlbumL(selections[i].iId2, aAttrs, aArray);
                    }
                }
            else
                {
                // One album
                iDbHandler->GetSongsMatchingAlbumL(aPath.Id(idIndex).iId2, aAttrs, aArray);
                }

				// added for ganes
                SetMediaGeneralAttributesL(aEntries, EMPXItem, EMPXAlbum, iMusicLibraryTitles->MdcaPoint(EBrowseAlbumSong));

            MPX_PERF_END(CMPXDbPlugin_DoOpenBrowseAlbumL_AllSongs);
            break;
            }

        // A song in an album
        case 4:
            {
            MPX_PERF_START(CMPXDbPlugin_DoOpenBrowseAlbumL_Song);

            iDbHandler->GetSongL(aPath.Id(idIndex).iId2, aAttrs, *aArray);
            isASong = ETrue;

            MPX_PERF_END(CMPXDbPlugin_DoOpenBrowseAlbumL_Song);
            break;
            }

        default:
            {
            MPX_DEBUG2("CMPXDbPlugin_DoOpenBrowseAlbumL: Invalid levels[%d]", levels);
            User::Leave(KErrNotSupported);
            }
        }

    CleanupStack::PopAndDestroy(&selections);
    return isASong;
    }

// ----------------------------------------------------------------------------
// Handles OpenL called for EBrowsePlaylist
// ----------------------------------------------------------------------------
//
TBool CMPXDbPlugin::DoOpenBrowsePlaylistL(
    const CMPXCollectionPath& aPath,
    const TArray<TMPXAttribute>& aAttrs,
    CMPXMedia& aEntries,
    CMPXMediaArray* aArray)
    {
    MPX_FUNC("CMPXDbPlugin::DoOpenBrowsePlaylistL");

    TBool isASong(EFalse);
    TInt levels(aPath.Levels());
    TInt idIndex(levels - 1);

    RArray<TMPXItemId> selections;
    CleanupClosePushL(selections);
    aPath.SelectionL(selections);

    switch (levels)
         {
         case 2:
            {
            // All playlists
            MPX_PERF_START(CMPXDbPlugin_DoOpenBrowsePlaylistL_All);

            iDbHandler->GetAllPlaylistsL(aArray, aAttrs);
            iDbHandler->GetAllSystemPlaylistNamesL(aArray);

            SetMediaGeneralAttributesL(aEntries, EMPXGroup, EMPXPlaylist,
                iMusicLibraryTitles->MdcaPoint(EBrowsePlaylist));

            MPX_PERF_END(CMPXDbPlugin_DoOpenBrowsePlaylistL_All);
            break;
            }

         // All songs in a playlist
         case 3:
            {
            MPX_PERF_START(CMPXDbPlugin_DoOpenBrowsePlaylistL_AllSongs);

            if (selections.Count())
                {
                const TInt count(aPath.Selection().Count());
                for (TInt i = 0; i < count; ++i)
                    {
                    iDbHandler->GetSongsMatchingPlaylistL(selections[i].iId2, aAttrs, aArray);
                    }
                }
            else
                {
                iDbHandler->GetSongsMatchingPlaylistL(aPath.Id (idIndex).iId2, aAttrs, aArray);
                }


            SetMediaGeneralAttributesL(aEntries, EMPXItem, EMPXPlaylist, aPath.Id(idIndex).iId2);

            // populate EMPXMediaGeneralNonPermissibleActions
            if (iDbHandler->IsAutoPlaylistL(aPath.Id(idIndex).iId2))
                {
                // set non-permissible actions to not writable and cacheable
                aEntries.SetTObjectValueL<TMPXGeneralNonPermissibleActions>(
                    KMPXMediaGeneralNonPermissibleActions, (TMPXGeneralNonPermissibleActions)(EMPXWrite | EMPXCache));
                }

            MPX_PERF_END(CMPXDbPlugin_DoOpenBrowsePlaylistL_AllSongs);
            break;
            }

         // Specific song in a playlist
         case 4:
            {
            MPX_PERF_START(CMPXDbPlugin_DoOpenBrowsePlaylistL_Song);

            iDbHandler->GetPlaylistSongL(aPath.Id(idIndex).iId2, aPath.Id(idIndex - 1).iId2,
                aAttrs, *aArray);
            isASong = ETrue;

            MPX_PERF_END(CMPXDbPlugin_DoOpenBrowsePlaylistL_Song);
            break;
            }

         default:
            {
            MPX_DEBUG2("CMPXDbPlugin_DoOpenBrowsePlaylistL: Invalid levels[%d]", levels);
            User::Leave(KErrNotSupported);
            }
       }

    CleanupStack::PopAndDestroy(&selections);
    return isASong;
    }

// ----------------------------------------------------------------------------
// Handles OpenL called for EBrowseGenre
// ----------------------------------------------------------------------------
//
TBool CMPXDbPlugin::DoOpenBrowseGenreL(
    const CMPXCollectionPath& aPath,
    const TArray<TMPXAttribute>& aAttrs,
    CMPXMedia& aEntries,
    CMPXMediaArray* aArray)
    {
    MPX_FUNC("CMPXDbPlugin::DoOpenBrowseGenreL");

    TBool isASong(EFalse);
    TInt levels(aPath.Levels());
    TInt idIndex(levels - 1);

    RArray<TMPXItemId> selections;
    CleanupClosePushL(selections);
    aPath.SelectionL(selections);

    switch (levels)
        {
        // All genres
         case 2:
            {
            MPX_PERF_START(CMPXDbPlugin_DoOpenBrowseGenreL_All);

            iDbHandler->GetAllGenresL(aAttrs, aArray);
            SetMediaGeneralAttributesL(aEntries, EMPXGroup, EMPXGenre,
                iMusicLibraryTitles->MdcaPoint(EBrowseGenre));

            MPX_PERF_END(CMPXDbPlugin_DoOpenBrowseGenreL_All);
            break;
            }

        // All songs of a genre
        case 3:
            {
            MPX_PERF_START(CMPXDbPlugin_DoOpenBrowseGenreL_AllSongs);

            if (selections.Count())
                {
                const TInt count(aPath.Selection().Count());
                for (TInt i = 0; i < count; ++i)
                    {
                    iDbHandler->GetSongsMatchingGenreL(selections[i].iId2, aAttrs, aArray);
                    }
                }
            else
                {
                iDbHandler->GetSongsMatchingGenreL(aPath.Id(idIndex).iId2, aAttrs, aArray);
                }
            SetMediaGeneralAttributesL(aEntries, EMPXItem, EMPXGenre, aPath.Id(idIndex).iId2);

            MPX_PERF_END(CMPXDbPlugin_DoOpenBrowseGenreL_AllSongs);
            break;
            }

        // Specific song in a genre
        case 4:
            {
            MPX_PERF_START(CMPXDbPlugin_DoOpenBrowseGenreL_Song);

            iDbHandler->GetSongL(aPath.Id(idIndex).iId2, aAttrs, *aArray);
            isASong = ETrue;

            MPX_PERF_END(CMPXDbPlugin_DoOpenBrowseGenreL_Song);
            break;
            }

        default:
            {
            MPX_DEBUG2("CMPXDbPlugin_DoOpenBrowseGenreL: Invalid levels[%d]", levels);
            User::Leave(KErrNotSupported);
            }
        }

    CleanupStack::PopAndDestroy(&selections);
    return isASong;
    }

// ----------------------------------------------------------------------------
// Handles OpenL called for EBrowseComposer
// ----------------------------------------------------------------------------
//
TBool CMPXDbPlugin::DoOpenBrowseComposerL(
    const CMPXCollectionPath& aPath,
    const TArray<TMPXAttribute>& aAttrs,
    CMPXMedia& aEntries,
    CMPXMediaArray* aArray)
    {
    MPX_FUNC("CMPXDbPlugin::DoOpenBrowseComposerL");

    TBool isASong(EFalse);
    TInt levels(aPath.Levels());
    TInt idIndex(levels - 1);

    RArray<TMPXItemId> selections;
    CleanupClosePushL(selections);
    aPath.SelectionL(selections);

    switch (levels)
        {
        // All composers
        case 2:
            {
            MPX_PERF_START(CMPXDbPlugin_DoOpenBrowseComposerL_All);

            iDbHandler->GetAllComposersL(aAttrs, aArray);
            SetMediaGeneralAttributesL(aEntries, EMPXGroup, EMPXComposer,
                iMusicLibraryTitles->MdcaPoint(EBrowseComposer));

            MPX_PERF_END(CMPXDbPlugin_DoOpenBrowseComposerL_All);
            break;
            }

        // All songs of a composer
        case 3:
            {
            MPX_PERF_START(CMPXDbPlugin_DoOpenBrowseComposerL_AllSongs);
            if (selections.Count())
                {
                const TInt count(aPath.Selection().Count());
                for (TInt i = 0; i < count; ++i)
                    {
                    iDbHandler->GetSongsMatchingComposerL(selections[i].iId2, aAttrs, aArray);
                    }
                }
            else
                {
                iDbHandler->GetSongsMatchingComposerL(aPath.Id(idIndex).iId2, aAttrs, aArray);
                }
            SetMediaGeneralAttributesL(aEntries, EMPXItem, EMPXComposer, aPath.Id(idIndex).iId2);

            MPX_PERF_END(CMPXDbPlugin_DoOpenBrowseComposerL_AllSongs);
            break;
            }

        // Specific song of a composer
        case 4:
            {
            MPX_PERF_START(CMPXDbPlugin_DoOpenBrowseComposerL_Song);

            iDbHandler->GetSongL(aPath.Id(idIndex).iId2, aAttrs, *aArray);
            isASong = ETrue;

            MPX_PERF_END(CMPXDbPlugin_DoOpenBrowseComposerL_Song);
            break;
            }

        default:
            {
            MPX_DEBUG2("CMPXDbPlugin_DoOpenBrowseComposerL: Invalid levels[%d]", levels);
            User::Leave(KErrNotSupported);
            }
        }

    CleanupStack::PopAndDestroy(&selections);
    return isASong;
    }

// ----------------------------------------------------------------------------
// Process the OpenL method with open mode EMPXOpenPlaylistOnly
// ----------------------------------------------------------------------------
//
CMPXCollectionPath* CMPXDbPlugin::DoOpenPlaylistL(
    const CMPXCollectionPath& aPath,
    const TArray<TMPXAttribute>& aAttrs )
    {
    MPX_FUNC("CMPXDbPlugin::DoOpenPlaylistL");

    RArray<TMPXItemId> ids;
    CleanupClosePushL(ids);

    CMPXMedia* entries = CMPXMedia::NewL();
    CleanupStack::PushL(entries);

    CMPXCollectionPath* path = CMPXCollectionPath::NewL(aPath);
    CleanupStack::PushL(path);

    // Go through the browse path
    TInt levels(aPath.Levels());
    if (levels == 2)
        {
        // Create a new collection path
        CleanupStack::PopAndDestroy( path );
        path = CMPXCollectionPath::NewL();
        CleanupStack::PushL( path );

        // Always return all songs here
        ids.Reset();
        ids.AppendL( KDBPluginUid );
        path->AppendL(ids.Array());
        path->SelectL((TMPXItemId) KDBPluginUid);

        ids.Reset();
        ids.AppendL(EBrowseAll);
        path->AppendL(ids.Array());
        path->SelectL((TMPXItemId) EBrowseAll);
        path->Set(EMPXOpenPlaylistOnly);

        // Get all item IDs
        CMPXMediaArray* array = CMPXMediaArray::NewL();
        CleanupStack::PushL(array);

        DoOpenBrowseAllL(*path, aAttrs, *entries, array);

        entries->SetCObjectValueL(KMPXMediaArrayContents, array);
        entries->SetTObjectValueL<TInt>(KMPXMediaArrayCount, array->Count());

        CleanupStack::PopAndDestroy(array);

        DoAppendLevelL(*path, *entries);
        }
    else if (levels > 2)
        {
        switch (aPath.Id(1).iId2)
            {
            case EBrowseAll:
                {
                path->Set(EMPXOpenPlaylistOnly);
                // Returns the same path that we copied
                break;
                }
            case EBrowseArtist:
                {
                if (levels == 3)
                    {
                    // return all songs of a particular artist (currently highlighted)
                    path->Set(EMPXOpenGroupOrPlaylist);
                    ids.Reset();
                    ids.Append(aPath.Id(2));
                    path->AppendL(ids.Array());
                    path->SelectL(aPath.Id(2));
                    path->Set(EMPXOpenPlaylistOnly);

                    // Opens all songs of an artist and create the corresponding
                    // Collection playlist by appending all songs of an artist to
                    // the collection path
                    //
                    DoOpenL(*path, aAttrs, *entries, NULL);
                    DoAppendLevelL(*path, *entries);
                    }
                else if (levels == 4)
                    {
                    // Open the album of an artist and create the corresponding
                    // Collection playlist by appending all songs of an artist to
                    // the collection path
                    //
                    path->Set(EMPXOpenPlaylistOnly);
                    DoOpenL(*path, aAttrs, *entries, NULL);
                    DoAppendLevelL(*path, *entries);
                    }
                else
                    {
                    // case is a song no need to open again!
                    }

                break;
                }
            // Playlist, album, genre and composer easier, only 2 levels deep
            // plugin | category | category contents | songs of category
            //
            case EBrowsePlaylist:
            case EBrowseAlbum:
            case EBrowseGenre:
            case EBrowseComposer:
                {
                if (!DoOpenL(aPath, aAttrs, *entries, NULL))
                    {
                    // If it is not at a song level
                    // Append all entries to create collection path
                    //
                    path->Set(EMPXOpenPlaylistOnly);
                    DoAppendLevelL( *path, *entries );
                    }
                break;
                }
            default:
                {
                User::Leave(KErrNotSupported);
                }
            }
        }
    else  // levels < 2
        {
        User::Leave(KErrNotSupported);
        }

    // Cleanup
    CleanupStack::Pop(path);
    CleanupStack::PopAndDestroy(entries);
    CleanupStack::PopAndDestroy(&ids);

    return path;
    }

// ----------------------------------------------------------------------------
// Process the MediaL command
// ----------------------------------------------------------------------------
//
void CMPXDbPlugin::DoMediaL(
    const CMPXCollectionPath& aPath,
    const TArray<TMPXAttribute>& aAttrs,
    CMPXMedia& aEntries)
    {
    MPX_FUNC("CMPXDbPlugin::DoMediaL");

    // Fetch Media for root level
    //
    if (aPath.Levels() == 1) //root
        {
        DoRootMediaL( aAttrs, aEntries );
        }
    // Ensure the database has been merged before attempting MediaL()
    //
    else
        {
        CMPXMediaArray* array = CMPXMediaArray::NewL();
        CleanupStack::PushL(array);

        switch (aPath.Id(1).iId2)
            {
            case EBrowseAll:
                {
                DoAllSongsMediaL(aPath, aAttrs, aEntries, *array);
                break;
                } // end case EBrowseAll

            case EBrowseArtist:
                {
                DoArtistMediaL(aPath, aAttrs, aEntries, *array);
                break;
                } // end case EBrowseArtist

            case EBrowseAlbum:
                {
                DoCategoryMediaL(aPath, aAttrs, EMPXAlbum, aEntries, *array);
                break;
                } // end case EBrowseAlbum

            case EBrowsePlaylist:
                {
                DoCategoryMediaL(aPath, aAttrs, EMPXPlaylist, aEntries, *array);
                break;
                } // end case EBrowsePlaylist

            case EBrowseGenre:
                {
                DoCategoryMediaL(aPath, aAttrs, EMPXGenre, aEntries, *array);
                break;
                } // end case EBrowseGenre

            case EBrowseComposer:
                {
                DoCategoryMediaL(aPath, aAttrs, EMPXComposer, aEntries, *array);
                break;
                } // end case EBrowseComposer
#ifdef __ENABLE_PODCAST_IN_MUSIC_MENU
            case EBrowsePodcasts:
                {
                break;
                }
#endif
            default:
                {
                User::Leave(KErrArgument);
                }
            } // end switch(aPath.id(1)

        if (array->Count() > 0)
            {
            aEntries.SetCObjectValueL(KMPXMediaArrayContents, array);
            aEntries.SetTObjectValueL<TInt>(KMPXMediaArrayCount, array->Count());
            }
        CleanupStack::PopAndDestroy(array);
        }
    // Else case cannot leave, because this will happen when we have no disk space to
    // perform the merging. It should NOT leave.
    //
    }

// ----------------------------------------------------------------------------
// Find the collection media for root level
// ----------------------------------------------------------------------------
//
void CMPXDbPlugin::DoRootMediaL(
    const TArray<TMPXAttribute>& aAttrs,
    CMPXMedia& aMedia )
    {
    MPX_FUNC("CMPXDbPlugin::DoRootMediaL");

    TInt count(aAttrs.Count());
#ifndef __ENABLE_PODCAST_IN_MUSIC_MENU
    aMedia.SetTObjectValueL<TMPXGeneralNonPermissibleActions> (
            KMPXMediaGeneralNonPermissibleActions, (TMPXGeneralNonPermissibleActions)(EMPXWrite | EMPXCache) );
#endif // __ENABLE_PODCAST_IN_MUSIC_MENU
    for (TInt i = 0; i < count; ++i)
        {
        if (aAttrs[i].ContentId() == KMPXMediaIdGeneral)
            {
            TUint att(aAttrs[i].AttributeId());
            if (att & EMPXMediaGeneralTitle)
                {
                HBufC* title(iResource->ReadHBufCL(R_MPX_QTN_MUS_MUSIC));
                CleanupStack::PushL(title);
                aMedia.SetTextValueL(KMPXMediaGeneralTitle, *title);
                CleanupStack::PopAndDestroy(title);
                }
            if (att & EMPXMediaGeneralSubTitle)
                {
                TInt numSongs(iDbHandler->NumberOfItemsL(EMPXSong));
                aMedia.SetTObjectValueL<TInt>(KMPXMediaGeneralCount, numSongs);

                HBufC* text(iResource->ReadHBufCL((1 == numSongs) ?
                    R_MPX_QTN_MUS_MUSIC_ONE_SONG : R_MPX_QTN_MUS_MUSIC_NUM_SONGS));

                CleanupStack::PushL(text);
                aMedia.SetTextValueL(KMPXMediaGeneralSubTitle, *text);
                CleanupStack::PopAndDestroy(text);
                }
            if (att & EMPXMediaGeneralIcon)
                {
                TIconInfo icon;
                icon.bmpfile = KMPlayerDbPluginMbmFile;
                icon.bitmapId = EMbmMpxdbhgpluginQgn_graf_mup_dlst_music;
                icon.maskId = EMbmMpxdbhgpluginQgn_graf_mup_dlst_music_mask;
                aMedia.SetTObjectValueL<TIconInfo>(KMPXMediaGeneralIcon, icon);
                }
            } // if
        } // for
    }

// ----------------------------------------------------------------------------
// Find the collection media for all songs category
// ----------------------------------------------------------------------------
//
void CMPXDbPlugin::DoAllSongsMediaL(
    const CMPXCollectionPath& aPath,
    const TArray<TMPXAttribute>& aAttrs,
    CMPXMedia& aEntries,
    CMPXMediaArray& aMediaArray)
    {
    MPX_FUNC("CMPXDbPlugin::DoAllSongsMediaL");

    TInt levels(aPath.Levels());

    switch (levels)
       {
       // All songs
       case 2:
            {
            MPX_PERF_START(CMPXDbPlugin_DoAllSongsMediaL_All);
            DoRootCategoryMediaL(aAttrs, EBrowseAll, EMPXSong, aEntries);
            MPX_PERF_END(CMPXDbPlugin_DoAllSongsMediaL_All);
            break;
            }

         // A Song in all songs
         case 3:
            {
            MPX_PERF_START(CMPXDbPlugin_DoAllSongsMediaL_Song);
            GetSongInfoL(aPath, aAttrs, aEntries, aMediaArray);
            MPX_PERF_END(CMPXDbPlugin_DoAllSongsMediaL_Song);
            break;
            }

         default:
            {
            MPX_DEBUG2("CMPXDbPlugin_DoAllSongsMediaL: Invalid levels[%d]", levels);
            User::Leave(KErrNotSupported);
            }
        } // end switch(levels)
    }

// ----------------------------------------------------------------------------
// Find the collection media for artists category
// ----------------------------------------------------------------------------
//
void CMPXDbPlugin::DoArtistMediaL (
    const CMPXCollectionPath& aPath,
    const TArray<TMPXAttribute>& aAttrs,
    CMPXMedia& aEntries,
    CMPXMediaArray& aMediaArray)
    {
    MPX_FUNC("CMPXDbPlugin::DoArtistMediaL");

    TInt levels(aPath.Levels());
    TInt count(aPath.Selection().Count());

     // All artists
    if (levels == 2)
        {
        MPX_PERF_START(CMPXDbPlugin_DoArtistMediaL_All);
        DoRootCategoryMediaL(aAttrs, EBrowseArtist, EMPXArtist, aEntries);
        MPX_PERF_END(CMPXDbPlugin_DoArtistMediaL_All);
        }
    else if ((levels == 3) && count) // multiple artists selected
        {
        RArray<TMPXItemId> selections;
        CleanupClosePushL(selections);
        aPath.SelectionL(selections);

        for (TInt i = 0; i < count; ++i)
            {
            CMPXMedia* artist = CMPXMedia::NewL();
            CleanupStack::PushL(artist);
            iDbHandler->GetCategoryL(selections[i].iId2, EMPXArtist, aAttrs, artist);
            aMediaArray.AppendL(*artist);
            CleanupStack::PopAndDestroy(artist);
            }

        CleanupStack::PopAndDestroy(&selections);
        }
    else if (levels == 3) // single artist selected
        {
        iDbHandler->GetCategoryL(aPath.Id(2).iId2, EMPXArtist, aAttrs, &aEntries);
        }
    else if (levels == 4 && (aPath.Id(3) == aPath.Id(2))) // all songs for an artist
        {
        MPX_PERF_START(CMPXDbPlugin_DoArtistMediaL_AllSongs);
        // Calculate duration directly with SQL
        if (MPXDbCommonUtil::AttributeExists(aAttrs, KMPXMediaGeneralDuration))
            {
            DoDurationL(aEntries, EMPXArtist, aPath.Id(2));
            }

        MPX_PERF_END(CMPXDbPlugin_DoArtistMediaL_AllSongs);
        }
    else if ((levels == 4) && count) // multiple albums of an artist
        {
        MPX_PERF_START(CMPXDbPlugin_DoArtistMediaL_AllAlbums);

        RArray<TMPXItemId> selections;
        CleanupClosePushL(selections);
        aPath.SelectionL(selections);

        for (TInt i = 0; i < count; ++i)
            {
            CMPXMedia* media = CMPXMedia::NewL();
            CleanupStack::PushL(media);
            iDbHandler->GetCategoryL(selections[i].iId2, EMPXAlbum, aAttrs, media);
            aMediaArray.AppendL(*media);
            CleanupStack::PopAndDestroy(media);
            }

        CleanupStack::PopAndDestroy(&selections);

        MPX_PERF_END(CMPXDbPlugin_DoArtistMediaL_AllAlbums);
        }
    else if (levels == 4) // one album of an artist
        {
        MPX_PERF_START(CMPXDbPlugin_DoArtistMediaL_OneAlbum);
        iDbHandler->GetCategoryL(aPath.Id(3).iId2, EMPXAlbum, aAttrs, &aEntries);

        // Calculate duration
        if (MPXDbCommonUtil::AttributeExists(aAttrs, KMPXMediaGeneralDuration))
            {
            DoDurationL(aEntries, EMPXArtist, aPath.Id(2), EMPXAlbum, aPath.Id(3));
            }

        MPX_PERF_END(CMPXDbPlugin_DoArtistMediaL_OneAlbum);
        }
     else if (levels == 5) // a song/songs in an album
        {
        MPX_PERF_START(CMPXDbPlugin_DoArtistMediaL_Song);
        GetSongInfoL(aPath, aAttrs, aEntries, aMediaArray);
        MPX_PERF_END(CMPXDbPlugin_DoArtistMediaL_Song);
        }
    else
        {
        MPX_DEBUG2("CMPXDbPlugin_DoArtistMediaL: Invalid levels[%d]", levels);
        User::Leave(KErrNotSupported);
        }
    }

// ----------------------------------------------------------------------------
// Find the collection media for all songs category
// ----------------------------------------------------------------------------
//
void CMPXDbPlugin::DoRootCategoryMediaL (
    const TArray<TMPXAttribute>& aAttrs,
    TMPXItemId aRootCategoryId,
    TMPXGeneralCategory aCategory,
    CMPXMedia& aEntries)
    {
    MPX_FUNC("CMPXDbPlugin::DoRootCategoryMediaL");

    TInt count(aAttrs.Count());
    for (TInt i = 0; i < count; ++i)
        {
        if (aAttrs[i].ContentId() == KMPXMediaIdGeneral)
            {
            TUint att(aAttrs[i].AttributeId());
            switch (att)
                {
                case EMPXMediaGeneralId:
                    {
                    aEntries.SetTObjectValueL<TMPXItemId>(KMPXMediaGeneralId, aRootCategoryId);
                    break;
                    }
                case EMPXMediaGeneralTitle:
                    {
                    aEntries.SetTextValueL(KMPXMediaGeneralTitle,
                        iMusicLibraryMenuTitles->MdcaPoint(BrowseTypeForCategory(aCategory)));
                    break;
                    }
                case EMPXMediaGeneralCount:
                    {
                    // count number of category
                    aEntries.SetTObjectValueL<TInt>(KMPXMediaGeneralCount,
                        iDbHandler->NumberOfItemsL(aCategory));
                    break;
                    }
                case EMPXMediaGeneralDuration:
                    {
                    if (aCategory == EMPXSong)
                        {
                        DoDurationL(aEntries, EMPXSong);
                        }
                    break;
                    }
                default:
                    // not supported
                    break;
                } // end switch
            } // end if
        } // end for

    aEntries.SetTObjectValueL<TMPXGeneralType>(KMPXMediaGeneralType, EMPXGroup);
    aEntries.SetTObjectValueL<TMPXGeneralCategory>(KMPXMediaGeneralCategory, aCategory);
    }

// ----------------------------------------------------------------------------
// Find the collection media for albums/playlists/genres/composers category
// ----------------------------------------------------------------------------
//
void CMPXDbPlugin::DoCategoryMediaL(
    const CMPXCollectionPath& aPath,
    const TArray<TMPXAttribute>& aAttrs,
    TMPXGeneralCategory aCategory,
    CMPXMedia& aEntries,
    CMPXMediaArray& aMediaArray)
    {
    MPX_FUNC("CMPXDbPlugin::DoCategoryMediaL");

    TInt levels(aPath.Levels());
    TInt count(aPath.Selection().Count());

    if (levels == 2) // all albums/playlists/genres/composers
        {
        MPX_PERF_START (CMPXDbPlugin_DoCategoryMediaL_All);
        DoRootCategoryMediaL(aAttrs, aPath.Id(1).iId2, aCategory, aEntries);
        MPX_PERF_END (CMPXDbPlugin_DoCategoryMediaL_All);
        }
    else if (levels == 3 && count) // multiple albums/playlists/genres/composers selected
        {
        RArray<TMPXItemId> selections;
        CleanupClosePushL(selections);
        aPath.SelectionL(selections);

        for (TInt i = 0; i < count; ++i)
            {
            CMPXMedia* media = CMPXMedia::NewL();
            CleanupStack::PushL(media);
            iDbHandler->GetCategoryL(selections[i].iId2, aCategory, aAttrs, media);
            aMediaArray.AppendL(*media);
            CleanupStack::PopAndDestroy(media);
            }

        CleanupStack::PopAndDestroy(&selections);
        }
    else if (levels == 3) // all songs in an album/playlist/genre/composer
        {
        MPX_PERF_START(CMPXDbPlugin_DoCategoryMediaL_Category);
        TMPXItemId id = aPath.Id(2);
        iDbHandler->GetCategoryL(id.iId2, aCategory, aAttrs, &aEntries);

        // Calculate duration directly with SQL
        if (MPXDbCommonUtil::AttributeExists(aAttrs, KMPXMediaGeneralDuration))
            {
            DoDurationL(aEntries, aCategory, id);
            }

        TInt nonPermisAction( aEntries.ValueTObjectL<TInt>(KMPXMediaGeneralNonPermissibleActions));
        nonPermisAction |= EMPXCache;

        aEntries.SetTObjectValueL<TMPXGeneralNonPermissibleActions>(
                    KMPXMediaGeneralNonPermissibleActions, (TMPXGeneralNonPermissibleActions) nonPermisAction );

        MPX_PERF_END(CMPXDbPlugin_DoCategoryMediaL_Category);
        }
    else if (levels == 4) // a song/songs in an album/playlist/genre/composer
        {
        MPX_PERF_START(CMPXDbPlugin_DoCategoryMediaL_Song);
        GetSongInfoL(aPath, aAttrs, aEntries, aMediaArray);
        MPX_PERF_END(CMPXDbPlugin_DoCategoryMediaL_Song);
        }
    else
        {
        MPX_DEBUG2("CMPXDbPlugin__DoMediaL__EBrowseAlbum: Invalid levels[%d]", levels);
        User::Leave(KErrNotSupported);
        }
    }

// ----------------------------------------------------------------------------
// Set all the attributes in CMPXMedia corresponding to KMPXMediaIdDrm
// ----------------------------------------------------------------------------
//
void CMPXDbPlugin::DoSetMediaDrmL(
    CMPXMedia& aMedia,
    TUint aDrmAttributes,
    const TDesC& aLocation)
    {
    MPX_FUNC("CMPXDbPlugin::DoSetMediaDrmL");

    iDrmMediaUtility->InitL(aLocation);
    CleanupClosePushL(*iDrmMediaUtility);
    const CMPXMedia* drmMedia(iDrmMediaUtility->GetMediaL(aDrmAttributes));

    // Only get attributes if it's a DRM file
    if (drmMedia)
        {
        if ((aDrmAttributes & EMPXMediaDrmType) &&
            drmMedia->IsSupported(KMPXMediaDrmType))
            {
            aMedia.SetTObjectValueL(KMPXMediaDrmType,
                drmMedia->ValueTObjectL<TInt>(KMPXMediaDrmType));
            }
        if ((aDrmAttributes & EMPXMediaDrmRightsStatus) &&
            drmMedia->IsSupported(KMPXMediaDrmRightsStatus))
            {
            aMedia.SetTObjectValueL(KMPXMediaDrmRightsStatus,
                drmMedia->ValueTObjectL<TInt>(KMPXMediaDrmRightsStatus));
            }
        if ((aDrmAttributes & EMPXMediaDrmRightsType) &&
            drmMedia->IsSupported(KMPXMediaDrmRightsType))
            {
            aMedia.SetTObjectValueL(KMPXMediaDrmRightsType,
                drmMedia->ValueTObjectL<TInt>(KMPXMediaDrmRightsType));
            }
        if ((aDrmAttributes & EMPXMediaDrmCount) &&
            drmMedia->IsSupported(KMPXMediaDrmCount))
            {
            aMedia.SetTObjectValueL(KMPXMediaDrmCount,
                drmMedia->ValueTObjectL<TInt>(KMPXMediaDrmCount));
            }
        if ((aDrmAttributes & EMPXMediaDrmProtected) &&
            drmMedia->IsSupported(KMPXMediaDrmProtected))
            {
            aMedia.SetTObjectValueL(KMPXMediaDrmProtected,
                drmMedia->ValueTObjectL<TBool>(KMPXMediaDrmProtected));
            }
        if ((aDrmAttributes & EMPXMediaDrmSendingAllowed) &&
            drmMedia->IsSupported(KMPXMediaDrmSendingAllowed))
            {
            aMedia.SetTObjectValueL(KMPXMediaDrmSendingAllowed,
                drmMedia->ValueTObjectL<TBool>(KMPXMediaDrmSendingAllowed));
            }
        if ((aDrmAttributes & EMPXMediaDrmCanSetAutomated) &&
            drmMedia->IsSupported(KMPXMediaDrmCanSetAutomated))
            {
            aMedia.SetTObjectValueL(KMPXMediaDrmCanSetAutomated,
                drmMedia->ValueTObjectL<TBool>(KMPXMediaDrmCanSetAutomated));
            }
        if ((aDrmAttributes & EMPXMediaDrmHasInfoUrl) &&
            drmMedia->IsSupported(KMPXMediaDrmHasInfoUrl))
            {
            aMedia.SetTObjectValueL(KMPXMediaDrmHasInfoUrl,
                drmMedia->ValueTObjectL<TBool>(KMPXMediaDrmHasInfoUrl));
            }
        if ((aDrmAttributes & EMPXMediaDrmHasPreviewUrl) &&
            drmMedia->IsSupported(KMPXMediaDrmHasPreviewUrl))
            {
            aMedia.SetTObjectValueL(KMPXMediaDrmHasPreviewUrl,
                drmMedia->ValueTObjectL<TBool>(KMPXMediaDrmHasPreviewUrl));
            }
        if ((aDrmAttributes & EMPXMediaDrmAboutToExpire) &&
            drmMedia->IsSupported(KMPXMediaDrmAboutToExpire))
            {
            aMedia.SetTObjectValueL( KMPXMediaDrmAboutToExpire,
                drmMedia->ValueTObjectL<TBool>(KMPXMediaDrmAboutToExpire));
            }
        if ((aDrmAttributes & EMPXMediaDrmStartTime) &&
            drmMedia->IsSupported(KMPXMediaDrmStartTime))
            {
            aMedia.SetTObjectValueL(KMPXMediaDrmStartTime,
                drmMedia->ValueTObjectL<TInt64>(KMPXMediaDrmStartTime));
            }
        if ((aDrmAttributes & EMPXMediaDrmEndTime) &&
            drmMedia->IsSupported(KMPXMediaDrmEndTime))
            {
            aMedia.SetTObjectValueL( KMPXMediaDrmEndTime,
                drmMedia->ValueTObjectL<TInt64>(KMPXMediaDrmEndTime));
            }
        if ((aDrmAttributes & EMPXMediaDrmIntervalStartTime) &&
            drmMedia->IsSupported(KMPXMediaDrmIntervalStartTime))
            {
            aMedia.SetTObjectValueL( KMPXMediaDrmIntervalStartTime,
                drmMedia->ValueTObjectL<TInt64>(KMPXMediaDrmIntervalStartTime));
            }
        if ((aDrmAttributes & EMPXMediaDrmAccumulatedTime) &&
            drmMedia->IsSupported(KMPXMediaDrmAccumulatedTime))
            {
            aMedia.SetTObjectValueL(KMPXMediaDrmAccumulatedTime,
                drmMedia->ValueTObjectL<TInt64>(KMPXMediaDrmAccumulatedTime));
            }
        if ((aDrmAttributes & EMPXMediaDrmInterval) &&
            drmMedia->IsSupported(KMPXMediaDrmInterval))
            {
            aMedia.SetTObjectValueL( KMPXMediaDrmInterval,
                drmMedia->ValueTObjectL<TTimeIntervalSeconds>(KMPXMediaDrmInterval));
            }
        }

    CleanupStack::PopAndDestroy(iDrmMediaUtility);
    }

// ----------------------------------------------------------------------------
// Add media objects to the array with attributes from song details
// ----------------------------------------------------------------------------
//
void CMPXDbPlugin::GetSongInfoL(
    const CMPXCollectionPath& aPath,
    const TArray<TMPXAttribute>& aAttrs,
    CMPXMedia& aEntry,
    CMPXMediaArray& aMediaArray)
    {
    MPX_FUNC("CMPXDbPlugin::GetSongInfoL");

    RArray<TInt> supportedIds;
    CleanupClosePushL(supportedIds);
    MPXDbCommonUtil::FillInSupportedUIDsL(aAttrs, supportedIds);

    RArray<TMPXItemId> selections;
    CleanupClosePushL(selections);
    aPath.SelectionL(selections);

    //
    // If we are trying to locate a song from a playlist, we should read available song
    // info from Playlist table first in case the song is located on a removable
    // drive and the drive is not currently present. This is achieved by supplying
    // playlist Id to GetSongMatchingSongIdL. When playlistId is 0, we are reading song
    // info directly from Songs table. If playlistId is specified, GetSongMatchingSongIdL
    // will populate song media from Playlist table and if Songs table for the drive
    // exists, song media will be overwritten with info from Songs table.
    //
    TMPXItemId playlistId(0);
    if (aPath.Id(1) == EBrowsePlaylist)
        {
        if (aPath.Levels() < 2)
            {
            User::Leave(KErrArgument);
            }

        playlistId = aPath.Id(aPath.Levels() - 2);
        }

    TInt countSelection(aPath.Selection().Count());
    if (countSelection)
        {
        // We have a selection, iterate it
        for (TInt selectionIndex = 0; selectionIndex < countSelection; ++selectionIndex)
            {
            CMPXMedia* newEntry = CMPXMedia::NewL(supportedIds.Array());
            CleanupStack::PushL(newEntry);

            DoGetSongInfoL(aAttrs, selections[selectionIndex].iId2, playlistId.iId2, *newEntry);

            aMediaArray.AppendL(*newEntry);
            CleanupStack::PopAndDestroy(newEntry);
            }
        }
    else
        {
        // No selection, get the attributes for the one song
        DoGetSongInfoL(aAttrs, aPath.Id(aPath.Levels() - 1).iId2, playlistId.iId2, aEntry);
        }

    CleanupStack::PopAndDestroy(&selections);
    CleanupStack::PopAndDestroy(&supportedIds);
    }

// ----------------------------------------------------------------------------
// Retrieves the attributes for a media object.
// ----------------------------------------------------------------------------
//
void CMPXDbPlugin::DoGetSongInfoL(
    const TArray<TMPXAttribute>& aAttrs,
    TInt aEntryId,
    TInt aPlaylistId,
    CMPXMedia& aEntry)
    {
    MPX_FUNC("CMPXDbPlugin::DoGetSongInfoL");

    if (aPlaylistId)
        {
        iDbHandler->GetPlaylistSongL(aEntryId, aPlaylistId, aAttrs, aEntry);
        }
    else
        {
        iDbHandler->GetSongL(aEntryId, aAttrs, aEntry);
        }

    const TDesC& location(aEntry.ValueText(KMPXMediaGeneralUri));

    // Check DRM Only if we have a location
    if (location != KNullDesC)
        {
        TUint drmAttributes(0);

        // Compact the attribute set
        TInt count(aAttrs.Count());
        for (TInt i = 0; i < count; ++i)
            {
            if (aAttrs[i].ContentId() == KMPXMediaIdDrm)
                {
                drmAttributes |= aAttrs[i].AttributeId();
                }
            }

        // Set the correct attributes to media, only if requested
        if (drmAttributes)
            {
            DoSetMediaDrmL(aEntry, drmAttributes, location);
            }
        }

    // Disable caching for any MediaL() returning song info.
    TInt nonPermisAction( aEntry.ValueTObjectL<TInt>(KMPXMediaGeneralNonPermissibleActions));
    nonPermisAction |= EMPXCache;

    aEntry.SetTObjectValueL<TMPXGeneralNonPermissibleActions>(
                KMPXMediaGeneralNonPermissibleActions, (TMPXGeneralNonPermissibleActions) nonPermisAction );
    }

// ----------------------------------------------------------------------------
// Find the collection details
// ----------------------------------------------------------------------------
//
void CMPXDbPlugin::DoHandleOtherMediaAttributesL(
    const TArray<TMPXAttribute>& aAttrs,
    const CMPXCollectionPath& aPath,
    CMPXMedia& aMedia)
    {
    MPX_FUNC("CMPXDbPlugin::DoHandleOtherMediaAttributesL");

    TInt count(aAttrs.Count());
    for (TInt i = 0; i < count; ++i)
        {
        if (aAttrs[i].ContentId() == KMPXMediaIdCollectionDetails)
            {
            TUint att(aAttrs[i].AttributeId());

            if (att & EMPXMediaColDetailNumberOfItems)
                {
                aMedia.SetTObjectValueL(KMPXMediaColDetailNumberOfItems,
                    iDbHandler->NumberOfItemsL(EMPXSong));
                }
            if (att & EMPXMediaColDetailDuration)
                {
                aMedia.SetTObjectValueL(KMPXMediaColDetailDuration,
                    DoDurationL(aMedia, EMPXSong));
                }
            if (att & EMPXMediaColTotalSize)
                {
                // todo
                TInt totalSize(0);
                aMedia.SetTObjectValueL(KMPXMediaColDetailTotalSize, totalSize);
                }
            if (att & EMPXMediaLastRefreshed)
                {
                TTime lastRefreshed(iDbHandler->GetLastRefreshedTimeL());
                aMedia.SetTObjectValueL(KMPXMediaColDetailLastRefreshed,
                    lastRefreshed.Int64());
                }
            if (att & EMPXMediaColDetailDBCreated)
                {
                aMedia.SetTObjectValueL(KMPXMediaColDetailDBCreated,
                    iDbHandler->DatabaseCreated());
                }
            if (att & EMPXMediaColDetailDBCorrupted)
                {
                aMedia.SetTObjectValueL(KMPXMediaColDetailDBCorrupted,
                    iDbHandler->IsDBCorruptedL());
                }
            }
        else if (aAttrs[i] == KMPXMediaGeneralPath)
            {
            aMedia.SetCObjectValueL(KMPXMediaGeneralPath,
                const_cast<CMPXCollectionPath*>(&aPath));
            }
        }
    }

// ----------------------------------------------------------------------------
// Remove an item from the collection database using the given path
// ----------------------------------------------------------------------------
//
CDesCArray* CMPXDbPlugin::DoRemoveL(
    const CMPXCollectionPath& aPath,
    CMPXMessageArray& aChangeMsgArray)
    {
    MPX_FUNC("CMPXDbPlugin::DoRemoveL");

    if (aPath.Levels() <= 1)
        {
        User::Leave(KErrNotSupported);
        }

    // Return file path for deleted item(s)
    //
    CDesCArray* fp = new(ELeave) CDesCArrayFlat(1);
    CleanupStack::PushL(fp);

    // Ids of the selected items
    RArray<TMPXItemId> selections;
    CleanupClosePushL(selections);
    aPath.SelectionL(selections);

    switch (aPath.Id(1).iId2)
        {
        case EBrowseAll:
            {
            DoRemoveFromAllSongsL(aPath, selections.Array(), *fp, aChangeMsgArray);
            }
            break;

        case EBrowseArtist:
            {
            DoRemoveFromArtistsL(aPath, selections.Array(), *fp, aChangeMsgArray);
            }
            break;

        case EBrowseAlbum: // deliberate fall through
        case EBrowseGenre: // deliberate fall through
        case EBrowseComposer: // deliberate fall through
            {
            DoRemoveFromCategoriesL(aPath, selections.Array(),
                CategoryForBrowseType(static_cast<TMCBrowseType>(aPath.Id(1).iId2)), *fp, aChangeMsgArray);
            }
            break;

        case EBrowsePlaylist:
            {
            DoRemoveFromPlaylistsL(aPath, selections.Array(), *fp, aChangeMsgArray);
            }
            break;

        default:
            {
            User::Leave(KErrArgument);
            }
        } // end switch (aPath.Id(1))

    MPX_DEBUG2("CMPXDbPlugin::RemoveL itemId[%d]", aPath.Id(aPath.Levels() - 1).iId2);

    CleanupStack::PopAndDestroy( &selections );
    CleanupStack::Pop(fp);

    return fp;
    }

// ----------------------------------------------------------------------------
// Remove an item from the collection database using the given media properties
// ----------------------------------------------------------------------------
//
void CMPXDbPlugin::DoRemoveL(
    const CMPXMedia& aMedia,
    TBool aDeleteRecord)
    {
    MPX_FUNC("CMPXDbPlugin::DoRemoveL(by media)");

    // Return deleted file paths to caller
    CDesCArray* fp = new(ELeave) CDesCArrayFlat(1);
    CleanupStack::PushL(fp);

    // a list of change event messages a result of the item being removed
    CMPXMessageArray* itemChangedMessages = CMPXMediaArray::NewL();
    CleanupStack::PushL(itemChangedMessages);

    TUint32 mediaId(0);

    // Removing a container of items
    //
    if (aMedia.IsSupported(KMPXMediaArrayContents))
        {
        MPX_DEBUG1("CMPXDbPlugin::RemoveL -- Removing a container of items");
        const CMPXMediaArray* media = aMedia.Value<CMPXMediaArray>(KMPXMediaArrayContents);
        if( !media )
            {
            User::Leave(KErrNoMemory);
            }
        const TInt mediaCount(media->Count());
        for (TInt i = 0; i < mediaCount; ++i)
            {
            CMPXMedia* entry = media->AtL(i);
            if (entry->IsSupported(KMPXMediaGeneralId))
                {
                mediaId = entry->ValueTObjectL<TMPXItemId>(KMPXMediaGeneralId);
                }
            else if (entry->IsSupported(KMPXMediaGeneralUri))
                {
                const TDesC& uri = entry->ValueText(KMPXMediaGeneralUri);
                mediaId = iDbHandler->GetSongIdMatchingUriL(uri);
                }
            else
                {
                // Unable to process this item
                continue;
                }

            iDbHandler->RemoveSongL(mediaId, *fp, *itemChangedMessages, aDeleteRecord);
            }
        }
    // Removing an item with known item id
    //
    else if (aMedia.IsSupported(KMPXMediaGeneralId))
        {
        MPX_DEBUG1("CMPXDbPlugin::RemoveL -- Removing an item by item id");
        mediaId =  aMedia.ValueTObjectL<TMPXItemId>(KMPXMediaGeneralId);

        if (MPX_ITEM_CATEGORY(mediaId) != EMPXPlaylist)
            {
            iDbHandler->RemoveSongL(mediaId, *fp, *itemChangedMessages, aDeleteRecord);
            }
        else
            {
            iDbHandler->RemovePlaylistL(mediaId, *fp, *itemChangedMessages);
            }
        }
    // Removing an item with known uri
    //
    else if (aMedia.IsSupported(KMPXMediaGeneralUri))
        {
        MPX_DEBUG1("CMPXDbPlugin::RemoveL -- Removing an item by uri");
        TPtrC uri = aMedia.ValueText( KMPXMediaGeneralUri );

        TMPXGeneralCategory category =
            aMedia.ValueTObjectL<TMPXGeneralCategory>(KMPXMediaGeneralCategory);

        if (category == EMPXSong)
            {
            mediaId = iDbHandler->GetSongIdMatchingUriL(uri);
            iDbHandler->RemoveSongL(mediaId, *fp, *itemChangedMessages, aDeleteRecord);
            }
        else if (category == EMPXPlaylist)
            {
            mediaId = iDbHandler->GetPlaylistIdMatchingUriL(uri);
            iDbHandler->RemovePlaylistL(mediaId, *fp, *itemChangedMessages);
            }
#ifdef ABSTRACTAUDIOALBUM_INCLUDED
        else if (category == EMPXAbstractAlbum )
            {
            mediaId = iDbHandler->GetAbstractAlbumIdMatchingUriL(uri);
            iDbHandler->RemoveAbstractAlbumL(mediaId, *itemChangedMessages, EFalse);
            }
#endif // ABSTRACTAUDIOALBUM_INCLUDED
        else
            {
            // otherwise unable to process this item
            }
        }
    else
        {
        MPX_DEBUG1("CMPXDbPlugin::RemoveL -- Unknown item for removal");
        User::Leave(KErrNotSupported);
        }

    iActiveTask->SetVisibleChange(CMPXDbActiveTask::EAllVisible);

    // Removing an item always invalidates all songs.
    //
    MPXDbCommonUtil::AddItemChangedMessageL(*itemChangedMessages, EBrowseAll,
                                            EMPXItemModified, EMPXCollection, KDBPluginUid);

    DoHandleChangeL(itemChangedMessages);

    CleanupStack::PopAndDestroy(itemChangedMessages);
    CleanupStack::PopAndDestroy(fp);
    }

// ----------------------------------------------------------------------------
// Remove media by path through a command
// ----------------------------------------------------------------------------
//
void CMPXDbPlugin::DoRemovePathL(
    CMPXCommand& aCmd)
    {
    MPX_FUNC("CMPXDbPlugin::DoRemovePathL(by command)");

    TInt removeError(KErrNone);
    TBool removeCompleted(ETrue);

    if (!aCmd.IsSupported(KMPXCommandCollectionRemovePath) ||
        !aCmd.IsSupported(KMPXCommandCollectionRemoveMediaCount))
        {
        removeError = KErrArgument;
        }
    else
        {
        CMPXCollectionPath* path =
            aCmd.ValueCObjectL<CMPXCollectionPath>(KMPXCommandCollectionRemovePath);
        CleanupStack::PushL(path);

        // in order to support cancel delete for a category, we need to adjust path. If
        // the path ends in a category, retrieve all songs under the selected category
        // and append a new level with all songs under the selected category
        DoAppendLevelL(*path);

        CMPXCollectionPath* iterationPath = CMPXCollectionPath::NewL(*path);
        CleanupStack::PushL(iterationPath);
        iterationPath->ClearSelection();

        // indices of the selected items
        TArray<TInt> selectionIndices = path->Selection();
        TInt count(selectionIndices.Count());

        // number of media items to remove in this iteration
        TInt removeCount = (aCmd.ValueTObjectL<TInt>(KMPXCommandCollectionRemoveMediaCount));

        // remove all in one shot if removeCount is 0 or negative
        if (removeCount <= 0)
            {
            removeCount = count;
            }

        // If the given path contains multiple selections, remove the first n selected media
        // and update the path so that client can use this path to call remove iteratively
        // until all selections are processed
        //
        if (count)
            {
            for (TInt i = 0; i < removeCount; ++i)
                {
                TInt index(selectionIndices[i]);

                MPX_DEBUG4(" path: selected item [index %d] [selectioncount %d] [remove count %d]", index, count, removeCount);

                iterationPath->SelectL(index);
                path->Remove(index);
                }

            aCmd.SetCObjectValueL(KMPXCommandCollectionRemovePath, path);

            // indicate to the client that subsequent remove command is required
            if ((count - removeCount) > 0)
                {
                removeCompleted = EFalse;
                }
            }

        // Remove the media specified by the path
        CDesCArray* fp(NULL);
        TBool supressMsgs(EFalse);
        CMPXMessageArray* msgAry(NULL);

        if (aCmd.IsSupported(KMPXCommandCollectionRemoveSuppressMsgs) &&
            aCmd.ValueTObjectL<TBool>(KMPXCommandCollectionRemoveSuppressMsgs))
            {
            // Msgs are stored in the command
            supressMsgs = ETrue;

            CMPXMessageArray* msgs( aCmd.Value<CMPXMessageArray>(KMPXCommandCollectionChangeMsgs) );
            User::LeaveIfNull( msgs );
            fp = DoRemoveL(*iterationPath, *msgs);
            }
        else
            {
            // Msgs will be sent after delete
            msgAry = CMPXMessageArray::NewL();
            CleanupStack::PushL(msgAry);
            fp = DoRemoveL(*iterationPath, *msgAry);
            }

        CleanupStack::PushL(fp);
        if (fp->MdcaCount() > removeCount)
            {
            removeError = KErrCorrupt;
            }
        CleanupStack::PopAndDestroy(fp);

        if (!supressMsgs)
            {
            // Send Change Messages
            iActiveTask->SetVisibleChange(CMPXDbActiveTask::EAllVisible);
            DoHandleChangeL(msgAry);
            CleanupStack::PopAndDestroy(msgAry);
            }

        // Cleanup
        CleanupStack::PopAndDestroy(iterationPath);
        CleanupStack::PopAndDestroy(path);
        }

    // mandatory return parameters
    aCmd.SetTObjectValueL<TInt>(KMPXCommandCollectionRemoveError, removeError);
    aCmd.SetTObjectValueL<TBool>(KMPXCommandCollectionRemoveCompleted, removeCompleted);
    }

// ----------------------------------------------------------------------------
// Remove media by CMPXMedia through a command
// ----------------------------------------------------------------------------
//
void CMPXDbPlugin::DoRemoveMediaL(
    CMPXCommand& aCmd)
    {
    MPX_FUNC("CMPXDbPlugin::DoRemoveMediaL(by command)");

    TInt error(KErrArgument);

    if (aCmd.IsSupported(KMPXCommandCollectionRemoveMedia))
        {
        CMPXMedia* media = aCmd.ValueCObjectL<CMPXMedia>(KMPXCommandCollectionRemoveMedia);
        CleanupStack::PushL(media);

        MPX_TRAP(error, DoRemoveL(*media,
            aCmd.ValueTObjectL<TBool>(KMPXCommandCollectionRemoveMediaDeleteRecord)));

        CleanupStack::PopAndDestroy(media);
        }

    aCmd.SetTObjectValueL<TInt>(KMPXCommandCollectionRemoveMediaError, error);
    }

// ----------------------------------------------------------------------------
// Remove a media/media items from All Songs view
// ----------------------------------------------------------------------------
//
void CMPXDbPlugin::DoRemoveFromAllSongsL(
    const CMPXCollectionPath& aPath,
    const TArray<TMPXItemId>& aSelections,
    CDesCArray& aUriArray,
    CMPXMessageArray& aItemChangedMessages)
    {
    MPX_FUNC("CMPXDbPlugin::DoRemoveFromAllSongsL");

    switch (aPath.Levels())
        {
        case 2:
            {
            // when the collection is removed, it's intended not to delete the files
            iDbHandler->RemoveEntireCollectionL();
            }
            break;

        case 3:
            {
            TInt count(aSelections.Count());
            if (count)
                {
                for (TInt i = 0; i < count; ++i)
                    {
                    iDbHandler->RemoveSongL(aSelections[i].iId2, aUriArray, aItemChangedMessages);
                    } // end for
                }
            else
                {
                iDbHandler->RemoveSongL(aPath.Id(aPath.Levels() - 1).iId2, aUriArray,
                     aItemChangedMessages);
                }
            }
            break;

        default:
            {
            MPX_DEBUG2("CMPXDbPlugin_DoRemoveFromAllSongsL: Invalid levels[%d]", aPath.Levels());
            User::Leave(KErrNotSupported);
            }
        }
    }

// ----------------------------------------------------------------------------
// Remove a media/media items from Artists view
// ----------------------------------------------------------------------------
//
void CMPXDbPlugin::DoRemoveFromArtistsL(
    const CMPXCollectionPath& aPath,
    const TArray<TMPXItemId>& aSelections,
    CDesCArray& aUriArray,
    CMPXMessageArray& aItemChangedMessages)
    {
    MPX_FUNC("CMPXDbPlugin::DoRemoveFromArtistsL");

    TInt levels(aPath.Levels());
    if (levels == 2)
        {
        // when the collection is removed, it's intended not to delete the files
        iDbHandler->RemoveEntireCollectionL();
        }
    else
        {
        TInt count(aSelections.Count());
        if (count)
            {
            for (TInt i = 0; i < count; ++i)
                {
                RemoveFromArtistsL(aPath, aSelections[i].iId2, aUriArray, aItemChangedMessages);
                }
            }
        else
            {
            RemoveFromArtistsL(aPath, aPath.Id(levels - 1).iId2, aUriArray, aItemChangedMessages);
            }
        }

    MPX_DEBUG2("CMPXDbPlugin__RemoveL__EBrowseArtist: levels[%d]", levels);
    }

// ----------------------------------------------------------------------------
// Remove a media item from Artists view
// ----------------------------------------------------------------------------
//
void CMPXDbPlugin::RemoveFromArtistsL(
    const CMPXCollectionPath& aPath,
    TUint32 aItemId,
    CDesCArray& aUriArray,
    CMPXMessageArray& aItemChangedMessages)
    {
    MPX_FUNC("CMPXDbPlugin::RemoveFromArtistsL");

    switch (aPath.Levels())
        {
        case 3:
            {
            iDbHandler->RemoveSongsMatchingCategoryL(EMPXArtist, aItemId, aUriArray, aItemChangedMessages);
            break;
            }
        case 4:
            {
            // remove the songs for the artist and album
            iDbHandler->RemoveSongsMatchingArtistAndAlbumL(aPath.Id(aPath.Levels() - 2), aItemId,
                aUriArray, aItemChangedMessages);
            break;
            }
        case 5:
            {
            iDbHandler->RemoveSongL(aItemId, aUriArray, aItemChangedMessages);
            break;
            }
        default:
            {
            User::Leave(KErrArgument);
            }
        }
    }

// ----------------------------------------------------------------------------
// Remove a media/media items from Albums/Genres/Composers view
// ----------------------------------------------------------------------------
//
void CMPXDbPlugin::DoRemoveFromCategoriesL(
    const CMPXCollectionPath& aPath,
    const TArray<TMPXItemId>& aSelections,
    TMPXGeneralCategory aCategory,
    CDesCArray& aUriArray,
    CMPXMessageArray& aItemChangedMessages)
    {
    MPX_FUNC("CMPXDbPlugin::DoRemoveFromCategoriesL");

    TInt levels(aPath.Levels());
    if (levels == 2)
        {
        // when the collection is removed, it's intended not to delete the files
        iDbHandler->RemoveEntireCollectionL();
        }
    else
        {
        TInt count(aSelections.Count());
        if (count)
            {
            for (TInt i = 0; i < count; ++i)
                {
                RemoveFromCategoriesL(aPath, aSelections[i].iId2, aCategory,
                    aUriArray, aItemChangedMessages);
                }
            }
        else
            {
            RemoveFromCategoriesL(aPath, aPath.Id(levels - 1).iId2, aCategory,
                aUriArray, aItemChangedMessages);
            }
        }

    MPX_DEBUG2("CMPXDbPlugin__RemoveL__EBrowseAlbum: levels[%d]", levels);
    }

// ----------------------------------------------------------------------------
// Remove a media item from Albums/Genres/Composers view
// ----------------------------------------------------------------------------
//
void CMPXDbPlugin::RemoveFromCategoriesL(
    const CMPXCollectionPath& aPath,
    TUint32 aItemId,
    TMPXGeneralCategory aCategory,
    CDesCArray& aUriArray,
    CMPXMessageArray& aItemChangedMessages)
    {
    MPX_FUNC("CMPXDbPlugin::RemoveFromCategoriesL");

    switch (aPath.Levels())
        {
        case 3:
            {
            iDbHandler->RemoveSongsMatchingCategoryL(aCategory, aItemId, aUriArray,
                aItemChangedMessages);
            break;
            }
        case 4:
            {
            iDbHandler->RemoveSongL(aItemId, aUriArray, aItemChangedMessages);
            break;
            }
        default:
            {
            User::Leave(KErrArgument);
            }
        }
    }

// ----------------------------------------------------------------------------
// Remove one or multiple media items from Playlists view
// ----------------------------------------------------------------------------
//
void CMPXDbPlugin::DoRemoveFromPlaylistsL(
    const CMPXCollectionPath& aPath,
    const TArray<TMPXItemId>& aSelections,
    CDesCArray& aUriArray,
    CMPXMessageArray& aItemChangedMessages)
    {
    MPX_FUNC("CMPXDbPlugin::DoRemoveFromPlaylistsL");

    TInt levels(aPath.Levels());

    // all playlists
    if (levels == 2)
        {
        // when the collection is removed, it's intended not to delete the files
        iDbHandler->RemoveAllPlaylistsL();
        }
    else
        {
        TArray<TInt> selectionIndices = aPath.Selection();
        TInt count(selectionIndices.Count());

        // multiple selections
        if (count)
            {
            for (TInt i = (count - 1); i >= 0; --i)
                {
                RemoveFromPlaylistsL(aPath, aSelections[i], selectionIndices[i],
                    aUriArray, aItemChangedMessages);
                }
            }
        // else no selection
        else
            {
            RemoveFromPlaylistsL(aPath, aPath.IdOfIndex(aPath.Index()), aPath.Index(),
                aUriArray, aItemChangedMessages);
            }
        }

    MPX_DEBUG2("CMPXDbPlugin__RemoveL__EBrowsePlaylist: levels[%d]", levels);
    }

// ----------------------------------------------------------------------------
// Remove a media item from Playlists view
// ----------------------------------------------------------------------------
//
void CMPXDbPlugin::RemoveFromPlaylistsL(
    const CMPXCollectionPath& aPath,
    const TMPXItemId& aItemId,
    TInt aIndex,
    CDesCArray& aUriArray,
    CMPXMessageArray& aItemChangedMessages)
    {
    MPX_FUNC("CMPXDbPlugin::RemoveFromPlaylistsL");

    switch (aPath.Levels())
        {
        case 3:
            {
            iDbHandler->RemovePlaylistL(aItemId.iId2, aUriArray, aItemChangedMessages);
            break;
            }
        case 4:
            {
            if ( !iDbHandler->InTransaction() )
                {
                iDbHandler->BeginTransactionL();
                }
            iDbHandler->RemoveSongFromPlaylistL(aPath.Id(aPath.Levels() - 2).iId2, aItemId,
                aIndex, aItemChangedMessages);
            break;
            }
        default:
            {
            User::Leave(KErrArgument);
            }
        }
    }

// ----------------------------------------------------------------------------
// Retrieve URIs associated with this file path for file deletion
// ----------------------------------------------------------------------------
//
void CMPXDbPlugin::DoRetrieveUriForDeletionL(
    CMPXCommand& aCmd)
    {
    MPX_FUNC("CMPXDbPlugin::DoRetrieveUriForDeletionL");

    // initialize mandatory return parameters
    aCmd.SetTObjectValueL<TInt>(KMPXCommandCollectionRetrieveUriError, KErrNone);

    if (!aCmd.IsSupported(KMPXCommandCollectionRetrievePath))
        {
        aCmd.SetTObjectValueL<TInt>(KMPXCommandCollectionRetrieveUriError, KErrArgument);
        }
    else
        {
        CMPXCollectionPath* path = aCmd.ValueCObjectL<CMPXCollectionPath>(KMPXCommandCollectionRetrievePath);
        CleanupStack::PushL(path);
        if (iFirstDeleteStep )
            {
            iSelections.Reset( );
        // in order to support cancel delete for a category, we need to adjust path. If
        // the path ends in a category, retrieve all songs under the selected category
        // and append a new level with all songs under the selected category
        DoAppendLevelL(*path);

        // Ids of the selected items
            path->SelectionL(iSelections );

        // single selection
            if (iSelections.Count()== 0 )
                {
                iSelections.AppendL(path->Id (path->Levels()- 1 ) );
                }
            }

        CDesCArray* fp = new(ELeave) CDesCArrayFlat(4);
        CleanupStack::PushL(fp);

        TInt count(iSelections.Count());
        TInt itemCount = count > KIncrementalDeleteCount ? KIncrementalDeleteCount : count;
        for (TInt i = 0; i < itemCount; ++i )
            {
            // do not report song URIs if collection path is for songs within a playlist, i.e.
            // EBrowsePlaylist and level 4, because client should not be deleting those song
            // files
            if (path->Id(1) != EBrowsePlaylist || path->Levels() !=4)
                {
                HBufC * uri = iDbHandler->GetUriMatchingIdL (iSelections[0].iId2 );
                CleanupStack::PushL(uri);
                fp->AppendL(*uri);
                CleanupStack::PopAndDestroy(uri);
                }
            iSelections.Remove(0);
            }

        aCmd.SetNoNewLCObjectL(KMPXCommandCollectionRetrieveMediaUriArray, fp);
        if (iFirstDeleteStep)
            {
        aCmd.SetCObjectValueL(KMPXCommandCollectionRetrievePath, path);
            }

        CleanupStack::PopAndDestroy(fp);
        CleanupStack::PopAndDestroy(path);
        }
    }

// ----------------------------------------------------------------------------
// Cleanup deleted records
// ----------------------------------------------------------------------------
//
void CMPXDbPlugin::CleanupDeletedRecordsL(
    CMPXCommand& aCmd)
    {
    MPX_FUNC("CMPXDbPlugin::CleanupDeletedRecordsL");

    MPX_TRAPD(error, iDbHandler->CleanupDeletedRecordsL());
    aCmd.SetTObjectValueL<TInt>(KMPXCommandCollectionCleanupError, error);
    }

// ----------------------------------------------------------------------------
// Find the duration
// ----------------------------------------------------------------------------
//
TInt CMPXDbPlugin::DoDurationL(
    CMPXMedia& aMedia,
    TMPXGeneralCategory aFirstCat,
    TMPXItemId aId,
    TMPXGeneralCategory aSecondCat,
    TMPXItemId aSubId)
    {
    MPX_FUNC("CMPXDbPlugin::DoDurationL");

    TInt duration(0);

    switch (aFirstCat)
        {
        case EMPXSong:
            {
            duration = iDbHandler->GetAllSongsDurationL();
            break;
            }
        case EMPXAlbum:
            {
            duration = iDbHandler->GetAlbumDurationL(aId.iId2);
            break;
            }
        case EMPXComposer:
            {
            duration = iDbHandler->GetComposerDurationL(aId.iId2);
            break;
            }
        case EMPXGenre:
            {
            duration = iDbHandler->GetGenreDurationL(aId.iId2);
            break;
            }
        case EMPXArtist:
            {
            if (aSecondCat == EMPXAlbum)
                {
                duration = iDbHandler->GetArtistAlbumDurationL(aId.iId2, aSubId.iId2);
                }
            else
                {
                duration = iDbHandler->GetArtistDurationL(aId.iId2);
                }
            break;
            }
        case EMPXPlaylist:
            {
            duration = iDbHandler->GetPlaylistDurationL(aId.iId2);
            break;
            }
        default:
            {
            User::Leave(KErrNotSupported);
            }
        }

    aMedia.SetTObjectValueL<TInt>(KMPXMediaGeneralDuration, duration);
    return duration;
    }

// ----------------------------------------------------------------------------
// Append a level to a collection path and set selection to the first item
// ----------------------------------------------------------------------------
//
TInt CMPXDbPlugin::DoAppendLevelL(
    CMPXCollectionPath& aPath,
    CMPXMedia& aMedia )
    {
    MPX_FUNC("CMPXDbPlugin::DoAppendLevelL");

    RArray<TMPXItemId> ids;
    CleanupClosePushL(ids);

    // Extract media array, and get all item ids
    //
    const CMPXMediaArray* mediaArray = aMedia.Value<CMPXMediaArray>(KMPXMediaArrayContents);
    if( !mediaArray )
        {
        User::Leave( KErrNoMemory );
        }

    TInt count(mediaArray->Count());
    if (count >= 0)
        {
        for (TInt i = 0; i < count; ++i)
            {
            TMPXItemId id = mediaArray->AtL(i)->ValueTObjectL<TMPXItemId>(KMPXMediaGeneralId);
            ids.AppendL(id);
            }

        // Put item id array into the path and select the first one
        aPath.AppendL(ids.Array());
        if (count > 0)
            {
            aPath.Set(0);
            }
        }

    CleanupStack::PopAndDestroy(&ids);
    return count;
    }

// ----------------------------------------------------------------------------
// Append a level to a collection path and set selection to all songs under the
// selected category/categories
// ----------------------------------------------------------------------------
//
void CMPXDbPlugin::DoAppendLevelL(
    CMPXCollectionPath& aPath)
    {
    MPX_FUNC("CMPXDbPlugin::DoAppendLevelL");

    TMPXItemId contextId(aPath.Id(1));
    TInt levels(aPath.Levels());

    if ((contextId == EBrowseAll) ||
        (contextId == EBrowsePlaylist))
        {
        return;
        }
    else if (levels == 3 || (levels == 4 && contextId == EBrowseArtist))
        {
        // retrieve songs in the selected category
        //
        CMPXMediaArray* songs = CMPXMediaArray::NewL();
        CleanupStack::PushL(songs);

        RArray<TMPXAttribute> attributes;
        CleanupClosePushL(attributes);
        attributes.AppendL(KMPXMediaGeneralId);

        // Ids of the selected items
        RArray<TMPXItemId> selections;
        CleanupClosePushL(selections);
        aPath.SelectionL(selections);

        // single selection
        if (selections.Count() == 0)
            {
            selections.AppendL(aPath.Id(aPath.Levels() - 1));
            }

        TInt count(selections.Count());

        // all songs for the selected artist
        if (contextId == EBrowseArtist && levels == 3)
            {
            for (TInt i = 0; i < count; ++i)
                {
                iDbHandler->GetSongsMatchingArtistL(selections[i].iId2, attributes.Array(), songs);
                }
            if (songs->Count())
                {
                aPath.AppendL(selections.Array());
                }
            }

        // all songs for the selected artist in the specified album
        else if ((contextId == EBrowseArtist) && (levels == 4))
            {
            for (TInt i = 0; i < count; ++i)
                {
                if (aPath.Id(2) == aPath.Id(3))
                    {
                    iDbHandler->GetSongsMatchingArtistL(aPath.Id(3).iId2,
                        attributes.Array(), songs);
                    }
                else
                    {
                    iDbHandler->GetSongsMatchingArtistAndAlbumL(aPath.Id(aPath.Levels() - 2),
                        selections[i].iId2, attributes.Array(), songs);
                    }
                }
            }

         // all songs for the selected album
        else if (contextId == EBrowseAlbum && levels == 3)
            {
            for (TInt i = 0; i < count; ++i)
                {
                iDbHandler->GetSongsMatchingAlbumL(selections[i], attributes.Array(), songs);
                }
            }

        // all songs for the selected genre
        else if (contextId == EBrowseGenre && levels == 3)
            {
            for (TInt i = 0; i < count; ++i)
                {
                iDbHandler->GetSongsMatchingGenreL(selections[i], attributes.Array(), songs);
                }
            }

        // all songs for the selected composer
        else if (contextId == EBrowseComposer && levels == 3)
            {
            for (TInt i = 0; i < count; ++i)
                {
                iDbHandler->GetSongsMatchingComposerL(selections[i], attributes.Array(), songs);
                }
            }
        else
            {
            // else do nothing
            }

        CleanupStack::PopAndDestroy(&selections);
        CleanupStack::PopAndDestroy(&attributes);

        // transform from CMPXMediaArray to RArray
        RArray<TMPXItemId> songIds;
        CleanupClosePushL(songIds);

        TInt songCount(songs->Count());
        for (TInt i = 0; i < songCount; ++i)
            {
            CMPXMedia* song = (*songs)[i];

            if (song->IsSupported(KMPXMediaGeneralId))
                {
                songIds.AppendL(song->ValueTObjectL<TMPXItemId>(KMPXMediaGeneralId));
                }
            }

        // modify the collection path. append another level with all songs under the selected
        // category/categories selected
        songCount = songIds.Count();

        if (songCount)
            {
            aPath.ClearSelection();
            aPath.AppendL(songIds.Array());

            // select all
            for (TInt i = 0; i < songCount; ++i)
                {
                aPath.SelectL(songIds[i]);
                }
            }

        CleanupStack::PopAndDestroy(&songIds);
        CleanupStack::PopAndDestroy(songs);
        }
    else
        {
        // do nothing
        }
    }

// ----------------------------------------------------------------------------
// Execute an Add task step
// ----------------------------------------------------------------------------
//
TBool CMPXDbPlugin::DoAddAsyncL()
    {
    MPX_FUNC("CMPXDbPlugin::DoAddAsyncL");

    TBool done(EFalse);
    const CMPXMedia* task = (iActiveTask->GetCommand().Value<CMPXMedia>(KMPXCommandColAddMedia));
    if( !task )
        {
        User::Leave(KErrNoMemory);
        }

    CMPXMessageArray& msgArray = iActiveTask->GetChangeMessages();

    if (!task->IsSupported(KMPXMediaGeneralType))
        {
        User::Leave(KErrArgument);
        }

    // Group of items or a single item
    //
    if (task->ValueTObjectL<TMPXGeneralType>(KMPXMediaGeneralType) == EMPXGroup)
        {
        if (!task->IsSupported(KMPXMediaArrayContents))
            {
            User::Leave(KErrArgument);
            }

        CMPXMediaArray* ary = task->Value<CMPXMediaArray>(KMPXMediaArrayContents);
        User::LeaveIfNull(ary);
        TInt step( iActiveTask->GetStep() );
        DoAddItemL( *ary->AtL(step), msgArray );

        if (++step == ary->Count())
            {
            done = ETrue;
            }
        }
    else // type == EMPXItem
        {
        TUint32 item = DoAddItemL( *task, msgArray );
        iActiveTask->GetCommand().SetTObjectValueL<TMPXItemId>( KMPXCommandColAddRtnId, item);
        done = ETrue;
        }

    iActiveTask->SetVisibleChange(CMPXDbActiveTask::EAllVisible);
    return done;
    }

// ----------------------------------------------------------------------------
// Add an item to the collection
// ----------------------------------------------------------------------------
//
TUint32 CMPXDbPlugin::DoAddL(
    const CMPXMedia& aMedia)
    {
    MPX_FUNC("CMPXDbPlugin::DoAddL");

    if (!aMedia.IsSupported(KMPXMediaGeneralType))
        {
        User::Leave(KErrArgument);
        }

    TUint32 itemId(0);
    CMPXMessageArray* changeMsgAry = CMPXMessageArray::NewL();
    CleanupStack::PushL(changeMsgAry);

    // start a transaction here
    if (!iDbHandler->InTransaction())
        {
        iDbHandler->BeginTransactionL();
        }

    // Group of items
    if (aMedia.ValueTObjectL<TMPXGeneralType>(KMPXMediaGeneralType) == EMPXGroup)
        {
        CMPXMediaArray* array = aMedia.Value<CMPXMediaArray>(KMPXMediaArrayContents);
        User::LeaveIfNull( array );

        TInt count(array->Count());
        for (TInt i = 0; i < count; ++i)
            {
            // ETrue indicates we are batch committing the songs.
            // This parameter is only used for the use case of adding
            // thousands of songs at a time.
            DoAddItemL(*array->AtL(i), *changeMsgAry, ETrue);
            }
        }
    else // single item
        {
        itemId = DoAddItemL(aMedia, *changeMsgAry);
        }

    // end transaction here.
    iDbHandler->EndTransactionL(KErrNone);

    iActiveTask->SetVisibleChange(CMPXDbActiveTask::EAllVisible);
    DoHandleChangeL(changeMsgAry);
    CleanupStack::PopAndDestroy(changeMsgAry);

    return itemId;
    }

// ----------------------------------------------------------------------------------------------------------
// Add an item to the collection
// ----------------------------------------------------------------------------------------------------------
//
TUint32 CMPXDbPlugin::DoAddItemL(
    const CMPXMedia& aMedia,
    CMPXMessageArray& aMessageArray,
    TBool aBatchCommit)
    {
    MPX_FUNC("CMPXDbPlugin::DoAddItemL");

    TUint32 itemId(0);
    if (!aMedia.IsSupported(KMPXMediaGeneralCategory))
        {
        User::Leave(KErrArgument);
        }

    switch (aMedia.ValueTObjectL<TMPXGeneralCategory>(KMPXMediaGeneralCategory))
        {
        case EMPXPlaylist:
            {
            if (!aMedia.IsSupported(KMPXMediaArrayContents))
                {
                User::Leave(KErrArgument);
                }

            if (aMedia.IsSupported(KMPXMediaGeneralId))
                {
                itemId = iDbHandler->AddSongToPlaylistL(aMedia);
                MPXDbCommonUtil::AddItemChangedMessageL(aMessageArray, itemId, EMPXItemModified,
                    EMPXPlaylist, KDBPluginUid);
                }
            else if (aMedia.IsSupported(KMPXMediaGeneralUri))
                {
                itemId = iDbHandler->AddPlaylistL(aMedia);
                MPXDbCommonUtil::AddItemChangedMessageL(aMessageArray, EBrowsePlaylist, EMPXItemInserted,
                    EMPXPlaylist, KDBPluginUid);
                }
            else
                {
                User::Leave(KErrArgument);
                }
            }
            break;
#ifdef ABSTRACTAUDIOALBUM_INCLUDED
       case EMPXAbstractAlbum:
            {
            if (aMedia.IsSupported(KMPXMediaGeneralUri))
                {
                //add abstractalbum to AbstractAlbum table
                itemId = iDbHandler->AddAbstractAlbumL(aMedia, &aMessageArray);

                //in case aMedia as mediaArray which contains songs as arrayContents, need to update all songs associated
                if ( aMedia.IsSupported(KMPXMediaArrayContents))
                    {
                    iDbHandler->UpdateSongsAbstractAlbumInfoL(aMedia, aMessageArray);
                    }
                }
            else
                {
                User::Leave(KErrArgument);
                }
            }
            break;
#endif // ABSTRACTAUDIOALBUM_INCLUDED
        case EMPXSong:
            {
            // For the use case of adding thousands of songs at once,
            // we do not create a new database transaction for each song;
            // Instead DoAddL() will batch 100 songs under a single transaction.
            // This enhancement improves performance with MMC-based databases.
            if (aBatchCommit)
                {
                itemId = iDbHandler->AddSongWithNoTransactionL(aMedia, &aMessageArray);
                }
            else
                {
                itemId = iDbHandler->AddSongL(aMedia, &aMessageArray);
                }

            MPXDbCommonUtil::AddItemChangedMessageL(aMessageArray, itemId, EMPXItemInserted,
                EMPXSong, KDBPluginUid);
            }
            break;

        default:
            {
            User::Leave(KErrNotSupported);
            }
        }

    return itemId;
    }

// ----------------------------------------------------------------------------
// Update the collection from a media
// ----------------------------------------------------------------------------
//
void CMPXDbPlugin::DoSetL(
    const CMPXMedia& aMedia )
    {
    MPX_FUNC("CMPXDbPlugin::DoSetL");

    if (!aMedia.IsSupported(KMPXMediaGeneralType))
        {
        User::Leave(KErrArgument);
        }

    CMPXDbActiveTask::TChangeVisibility visibleChange(CMPXDbActiveTask::ENotVisibile);

    CMPXMessageArray* changeMsgArray = CMPXMessageArray::NewL();
    CleanupStack::PushL(changeMsgArray);

    if (aMedia.ValueTObjectL<TMPXGeneralType>(KMPXMediaGeneralType) == EMPXGroup)
        {
        if (!aMedia.IsSupported(KMPXMediaArrayContents))
            {
            User::Leave(KErrArgument);
            }

        CMPXMediaArray* array = aMedia.Value<CMPXMediaArray>(KMPXMediaArrayContents);
        User::LeaveIfNull( array );
        TInt count( array->Count() );
        for (TInt i = 0; i < count; ++i)
            {
            visibleChange = (CMPXDbActiveTask::TChangeVisibility)(visibleChange | DoSetItemL(*array->AtL(i), *changeMsgArray));
            }
        }
    else
        {
        visibleChange = DoSetItemL(aMedia, *changeMsgArray);
        }

    // Handle Change Events
    if (visibleChange)
        {
        iActiveTask->SetVisibleChange(visibleChange);
        DoHandleChangeL(changeMsgArray);
        }
    CleanupStack::PopAndDestroy(changeMsgArray);
    }

// ----------------------------------------------------------------------------
// Execute a task step for async set
// ----------------------------------------------------------------------------
//
TBool CMPXDbPlugin::DoSetAsyncL()
    {
    MPX_FUNC("CMPXDbPlugin::DoSetAsyncL");

    TBool done(EFalse);
    CMPXMedia* task = iActiveTask->GetCommand().Value<CMPXMedia>(KMPXCommandColSetMedia);
    User::LeaveIfNull( task );

    CMPXMessageArray& msgArray = iActiveTask->GetChangeMessages();
    CMPXDbActiveTask::TChangeVisibility visibleChange(iActiveTask->GetVisibleChange());

    // Multiple steps can be in a transaction for faster response
    if( !iDbHandler->InTransaction() )
        {
        iDbHandler->BeginTransactionL();
        }

    if (!task->IsSupported(KMPXMediaGeneralType))
        {
        User::Leave(KErrArgument);
        }

    if (task->ValueTObjectL<TMPXGeneralType>(KMPXMediaGeneralType) == EMPXGroup)
        {
        if (!task->IsSupported(KMPXMediaArrayContents))
            {
            User::Leave(KErrArgument);
            }

        // Multiple items
        CMPXMediaArray* array = task->Value<CMPXMediaArray>(KMPXMediaArrayContents);
        User::LeaveIfNull( array );
        TInt step = iActiveTask->GetStep();
        visibleChange = (CMPXDbActiveTask::TChangeVisibility)(visibleChange | DoSetItemL(*array->AtL(step), msgArray));

        if (++step == array->Count())
            {
            done = ETrue;
            }
        }
    else // Single item
        {
        visibleChange = DoSetItemL(*task, msgArray);
        done = ETrue;
        }
    iActiveTask->SetVisibleChange(visibleChange);
    return done;
    }

// ----------------------------------------------------------------------------
// Update the collection from a media
// ----------------------------------------------------------------------------
//
CMPXDbActiveTask::TChangeVisibility CMPXDbPlugin::DoSetItemL(
    const CMPXMedia& aMedia,
    CMPXMessageArray& aMessageArray )
    {
    MPX_FUNC("CMPXDbPlugin::DoSetItemL");

    TMPXGeneralCategory category = aMedia.ValueTObjectL<TMPXGeneralCategory>(KMPXMediaGeneralCategory);

    CMPXDbActiveTask::TChangeVisibility visibleChange(CMPXDbActiveTask::ENotVisibile);
    switch (category)
        {
        case EMPXPlaylist:
            {
            if (aMedia.IsSupported(KMPXMediaArrayContents))
                {
                CMPXMessage* message = CMPXMedia::NewL();
                CleanupStack::PushL(message);

                iDbHandler->UpdatePlaylistSongsL(aMedia, *message);

                aMessageArray.AppendL(message); // ownership xfer
                CleanupStack::Pop(message);
                }
            else
                {
                iDbHandler->UpdatePlaylistL(aMedia, aMessageArray);
                }

            visibleChange = CMPXDbActiveTask::ESingleVisible;
            }
            break;
#ifdef ABSTRACTAUDIOALBUM_INCLUDED
        case EMPXAbstractAlbum:
            {
            //update all songes which associate with ABSTRACTALBUM
            if (aMedia.IsSupported(KMPXMediaGeneralUri))
                {
                //in case aMedia as mediaArray which contains songs as arrayContents, need to update all songs associated
                if ( aMedia.IsSupported(KMPXMediaArrayContents))
                    {
                    iDbHandler->UpdateSongsAbstractAlbumInfoL(aMedia, aMessageArray);
                    }
                //only update field values in abstractalbum table, or renaming (change uri) for abstractalbum table
                else
                    {
                    visibleChange = iDbHandler->UpdateAbstractAlbumL(aMedia, aMessageArray);
                    }
                }
            }
            break;
#endif // ABSTRACTAUDIOALBUM_INCLUDED
        case EMPXSong:
            {
            // a list of changed messages as a result of the song being updated
            visibleChange = iDbHandler->UpdateSongL(aMedia, aMessageArray);
            }
            break;

        default:
            {
            User::Leave(KErrNotSupported);
            }
            break;
        }
    return visibleChange; // ownership xfer
    }

// ----------------------------------------------------------------------------
// Sets the drm properties for a list of medias
// ----------------------------------------------------------------------------
//
void CMPXDbPlugin::DoSetDrmForArrayL(
    const CMPXMediaArray& mediaArray,
    const TArray<TMPXAttribute>& aAttrs)
    {
    MPX_FUNC("CMPXDbPlugin::DoSetDrmForArrayL");

    TUint drmAttributes(0);

    // Compact the attribute set
    //
    TInt attrCount(aAttrs.Count());
    for (TInt i = 0; i < attrCount; ++i)
        {
        if (aAttrs[i].ContentId() == KMPXMediaIdDrm)
            {
            drmAttributes |= aAttrs[i].AttributeId();
            }
        }

    // Fetch drm attributes for every item
    //
    if (drmAttributes)
        {
        TInt count(mediaArray.Count());
        for (TInt i = 0; i < count; ++i)
            {
            if (mediaArray[i]->IsSupported(KMPXMediaGeneralUri))
                {
                DoSetMediaDrmL(*mediaArray[i], drmAttributes,
                    mediaArray[i]->ValueText(KMPXMediaGeneralUri));
                }
            }
        }
    }

// ----------------------------------------------------------------------------
// Handle change events
// ----------------------------------------------------------------------------
//
void CMPXDbPlugin::HandleChangeL(
    const CMPXMessage& aMessage)
    {
    MPX_FUNC("CMPXDbPlugin::HandleChange");

    // check if message is filled
    if (aMessage.IsSupported(KMPXMessageGeneralId))
        {
#if _DEBUG
        PrintMessagesL(aMessage);
#endif // _DEBUG
        if(iRefreshing)
            {
            if (aMessage.IsSupported(KMPXMessageArrayContents))
                {
                const CMPXMessageArray* messageArray = aMessage.Value<CMPXMessageArray>(KMPXMessageArrayContents);
                if(messageArray)
                    {
                    CMPXMessage& message = *((*messageArray)[0]);
                    TMPXChangeEventType changeType( message.ValueTObjectL<TMPXChangeEventType>( KMPXMessageChangeEventType ) );
                    TMPXGeneralCategory cat(message.ValueTObjectL<TMPXGeneralCategory>(KMPXMessageMediaGeneralCategory));
                    if(changeType == EMPXItemInserted && (cat == EMPXSong || cat == EMPXPlaylist || cat == EMPXPodcast))
                        {
                        iObs->HandleMessage(aMessage);
                        }
                    }
                }
            else
                {
                TMPXChangeEventType changeType( aMessage.ValueTObjectL<TMPXChangeEventType>( KMPXMessageChangeEventType ) );
                TMPXGeneralCategory cat(aMessage.ValueTObjectL<TMPXGeneralCategory>(KMPXMessageMediaGeneralCategory));
                if(changeType == EMPXItemInserted && (cat == EMPXSong || cat == EMPXPlaylist || cat == EMPXPodcast))
                    {
                    iObs->HandleMessage(aMessage);
                    }
                }
            }
        else
            {
            if(!iMtpInUse)
                {
                iObs->HandleMessage(aMessage);
                }
            }
        }
    }

// ----------------------------------------------------------------------------
// Construct a CMPXMedia and call HandleChange
// ----------------------------------------------------------------------------
//
void CMPXDbPlugin::DoHandleChangeL(
    CMPXMessageArray* aItemChangedMessages,
    TMPXCommandId aCommandId )
    {
    MPX_FUNC("CMPXDbPlugin::DoHandleChangeL");

    if( (iActiveTask->GetVisibleChange() & CMPXDbActiveTask::EAllVisible)
        && (aCommandId == KMPXCommandIdCollectionSet ||
            aCommandId == KMPXCommandIdCollectionAdd ||
            aCommandId == KMPXCommandIdCollectionRemove ||
            aCommandId == KMPXCommandIdCollectionCompleteDelete ))
        {
        MPXDbCommonUtil::AddItemChangedMessageL(*aItemChangedMessages, EBrowseAll,
                                                 EMPXItemModified, EMPXCollection, KDBPluginUid);
        }
    // group change messages and send to collection client context
    //
    CMPXMessage* message = CMPXMessage::NewL();
    CleanupStack::PushL(message);

    message->SetTObjectValueL<TMPXMessageId>(KMPXMessageGeneralId, KMPXMessageIdItemChanged);
    message->SetCObjectValueL(KMPXMessageArrayContents, aItemChangedMessages);
    message->SetTObjectValueL<TInt>(KMPXMessageArrayCount, aItemChangedMessages->Count());

    HandleChangeL(*message);

    CleanupStack::PopAndDestroy(message);
    }

// ----------------------------------------------------------------------------
// Handle completion of operation
// ----------------------------------------------------------------------------
//
void CMPXDbPlugin::DoHandleOperationCompletedL(
    TInt aErr)
    {
    MPX_FUNC("CMPXDbPlugin::DoHandleOperationCompletedL");

    // Broadcase change messages
    //
    if (iActiveTask->GetVisibleChange())
        {
        DoHandleChangeL(&iActiveTask->GetChangeMessages(), iActiveTask->GetTask() );
        }

    // Callback to engine to signal completion
    // NOTE: Collection server immediately completes the async message when
    // Cancel is called, no need to callback to observer
    if (aErr != KErrCancel)
        {
        if( iActiveTask->GetTask() == KMPXCommandIdCollectionAdd )
            {
            iObs->HandleCommandComplete( &iActiveTask->GetCommand(), aErr );
            }
        else
            {
            iObs->HandleCommandComplete(NULL, aErr);
            }
        }

    if( iDbHandler->InTransaction() )
        {
        // Commit if cancelled
        TInt err(aErr);
        if( err == KErrCancel )
            {
            err = KErrNone;
            }
        iDbHandler->EndTransactionL( err );
        }
    }

// ----------------------------------------------------------------------------------------------------------
// Complete a delete operation
// ----------------------------------------------------------------------------------------------------------
//
void CMPXDbPlugin::DoHandleDeleteCompleteL(
    CMPXCommand& aCmd)
    {
    MPX_FUNC("CMPXDbPlugin::DoHandleDeleteCompleteL");
    iFirstDeleteStep = ETrue;
    iSelections.Reset();
    if ( iDbHandler->InTransaction() )
        {
        // if it can reach this point in a transaction, there's no error
        iDbHandler->EndTransactionL( KErrNone );
        }

    // Change messages
    if (aCmd.IsSupported(KMPXCommandCollectionDeleteMsgArray))
        {
        CMPXMessageArray* msgs = aCmd.Value<CMPXMessageArray>(KMPXCommandCollectionDeleteMsgArray);
        User::LeaveIfNull( msgs );
        iActiveTask->SetVisibleChange(CMPXDbActiveTask::EAllVisible);
        DoHandleChangeL(msgs, KMPXCommandIdCollectionCompleteDelete);
        }
    }

// ----------------------------------------------------------------------------------------------------------
// Reorder a song in a playlist
// ----------------------------------------------------------------------------------------------------------
//
void CMPXDbPlugin::DoReorderPlaylistL(
    const CMPXCommand& aCmd)
    {
    MPX_FUNC("CMPXDbPlugin::DoReorderPlaylistL");

    if (!aCmd.IsSupported(KMPXCommandReorderPlaylistId) ||
        !aCmd.IsSupported(KMPXCommandReorderSongId) ||
        !aCmd.IsSupported(KMPXCommandReorderOriginalOrdinal) ||
        !aCmd.IsSupported(KMPXCommandReorderNewOrdinal))
        {
        User::Leave(KErrArgument);
        }

    CMPXMessage* message = CMPXMedia::NewL();
    CleanupStack::PushL(message);

    iDbHandler->ReorderPlaylistL(
        aCmd.ValueTObjectL<TMPXItemId>(KMPXCommandReorderPlaylistId),
        aCmd.ValueTObjectL<TMPXItemId>(KMPXCommandReorderSongId),
        aCmd.ValueTObjectL<TUint>(KMPXCommandReorderOriginalOrdinal),
        aCmd.ValueTObjectL<TUint>(KMPXCommandReorderNewOrdinal),
        *message);

    HandleChangeL(*message);

    CleanupStack::PopAndDestroy(message);
    }

// ----------------------------------------------------------------------------------------------------------
// Get total songs and playlists count for a database
// ----------------------------------------------------------------------------------------------------------
//
void CMPXDbPlugin::DoGetCollectionCountL( const CMPXCommand& aCmd )
    {
    MPX_FUNC("CMPXDbPlugin::DoGetCollectionCountL");
    if (!aCmd.IsSupported(KMPXCommandCollectionCountDrive) ||
        !aCmd.IsSupported(KMPXCommandCollectionCountTable) )
        {
        User::Leave(KErrArgument);
        }

    TInt count = 0;
    TInt drive = aCmd.ValueTObjectL<TInt>(KMPXCommandCollectionCountDrive);
    TInt table = aCmd.ValueTObjectL<TInt>(KMPXCommandCollectionCountTable);
    switch(table)
        {
        case EMPXCollectionCountTrack:
            TRAPD( trackerr, count = (TInt)iDbHandler->GetMusicCountL(drive) );
            MPX_DEBUG2( "CMPXDbPlugin::DoGetCollectionCountL, trackerr =%d", trackerr );
            if ( trackerr == KErrCorrupt )
                {
                iDbHandler->CloseDatabaseL( drive );
                iDbHandler->RecreateDatabaseFileL( drive );
                iDbHandler->OpenDatabaseL( drive );
                count = (TInt)iDbHandler->GetMusicCountL(drive);
                }
            
            break;
        case EMPXCollectionCountPlaylist:
            TRAPD( playlisterr, count = (TInt)iDbHandler->GetPlaylistCountL(drive) );
            MPX_DEBUG2( "CMPXDbPlugin::DoGetCollectionCountL, playlisterr =%d", playlisterr );
            if ( playlisterr == KErrCorrupt )
                {
                iDbHandler->CloseDatabaseL( drive );
                iDbHandler->RecreateDatabaseFileL( drive );
                iDbHandler->OpenDatabaseL( drive );
                count = (TInt)iDbHandler->GetPlaylistCountL(drive);
                }
            break;
        case EMPXCollectionCountTotal:
            TRAPD( totalerr, count = (TInt)iDbHandler->GetTotalCountL(drive) );
            MPX_DEBUG2( "CMPXDbPlugin::DoGetCollectionCountL, totalerr =%d", totalerr );
            if ( totalerr == KErrCorrupt )
                {
                iDbHandler->CloseDatabaseL( drive );
                iDbHandler->RecreateDatabaseFileL( drive );
                iDbHandler->OpenDatabaseL( drive );
                count = (TInt)iDbHandler->GetTotalCountL(drive);
                }
            break;
        default:
            User::Leave(KErrArgument);
        }
    ((CMPXMedia&)aCmd).SetTObjectValueL<TInt>(KMPXCommandCollectionCountValue, count);
    }

// ----------------------------------------------------------------------------------------------------------
// Get URIs for all songs and file playlists in a database
// ----------------------------------------------------------------------------------------------------------
//
void CMPXDbPlugin::DoGetCollectionUriL( const CMPXCommand& aCmd )
    {
    MPX_FUNC("CMPXDbPlugin::DoGetCollectionCountL");
    if (!aCmd.IsSupported(KMPXCommandCollectionURIDrive) ||
        !aCmd.IsSupported(KMPXCommandCollectionURITable) ||
        !aCmd.IsSupported(KMPXCommandCollectionURIFromID) ||
        !aCmd.IsSupported(KMPXCommandCollectionURIRecords) )
        {
        User::Leave(KErrArgument);
        }

    TInt drive = aCmd.ValueTObjectL<TInt>(KMPXCommandCollectionURIDrive);
    TInt table = aCmd.ValueTObjectL<TInt>(KMPXCommandCollectionURITable);
    TInt fromID = aCmd.ValueTObjectL<TInt>(KMPXCommandCollectionURIFromID);
    TInt recnum = aCmd.ValueTObjectL<TInt>(KMPXCommandCollectionURIRecords);

    CDesCArray* uris = new(ELeave) CDesCArrayFlat(4);
    CleanupStack::PushL(uris);
    TInt lastID = 0;

    switch(table)
        {
        case EMPXCollectionURITrack:
            iDbHandler->GetMusicUriArrayL(drive, fromID, recnum, *uris, lastID);
            break;
        case EMPXCollectionURIPlaylist:
            iDbHandler->GetPlaylistUriArrayL(drive, fromID, recnum, *uris, lastID);
            break;
        default:
            User::Leave(KErrArgument);
        }

    ((CMPXMedia&)aCmd).SetNoNewLCObjectL(KMPXCommandCollectionURIList, uris);
    ((CMPXMedia&)aCmd).SetTObjectValueL(KMPXCommandCollectionURILastID, lastID);
    CleanupStack::PopAndDestroy(uris);
    }


// ----------------------------------------------------------------------------------------------------------
// Perform one step of the incremental operation
// ----------------------------------------------------------------------------------------------------------
//
void CMPXDbPlugin::DoIncrementalOpenL( const CMPXCommand& aCmd )
    {
    MPX_DEBUG1("CMPXDbPlugin::DoIncrementalOpenL <--");

    TInt offset = aCmd.ValueTObjectL<TInt>( KMPXCollectionCommandIdIncOpenLOffset );
    TInt numItems = aCmd.ValueTObjectL<TInt>( KMPXCollectionCommandIdIncOpenLNumItems );

    TReadDirection direction(EReadUnknown);
/*  Ascending and Decending reads are currently not used. We optimized for offset reads.
    if( aCmd.IsSupported(KMPXCollectionCommandIdIncOpenLAscDsc) &&
        aCmd.IsSupported(KMPXCollectionCommandIdIncOpenLKeyItem) )
        {
        direction = aCmd.ValueTObjectL<TReadDirection>(KMPXCollectionCommandIdIncOpenLAscDsc);
        }
*/
    CMPXCollectionPath* path =  aCmd.ValueCObjectL<CMPXCollectionPath>(KMPXCollectionCommandIdIncOpenLPath);
    CleanupStack::PushL( path );
    MPX_DEBUG_PATH( *path );

    // Switch on level and item selected
    //
    TInt levels( path->Levels() );
    switch( levels )
        {
        case 3:  // levels of 3 top level is not stripped
            {
            switch( path->Id(1).iId2 )
                {
                case EBrowseAll:
                    {
                    CMPXMedia* results = CMPXMedia::NewL();
                    CleanupStack::PushL( results );

                    TMPXOpenDataBlock block;
                    block.iOffset = offset;
                    block.iSize = numItems;

                    // Todo: this should come from the UI
                    RArray<TMPXAttribute> attrs;
                    CleanupClosePushL( attrs );
                    attrs.AppendL(TMPXAttribute(KMPXMediaIdGeneral,
                                   EMPXMediaGeneralId | EMPXMediaGeneralType | EMPXMediaGeneralCategory |
                                   EMPXMediaGeneralTitle | EMPXMediaGeneralFlags));
                    attrs.AppendL( TMPXAttribute(KMPXMediaIdMusic,
                                        EMPXMediaMusicArtist | EMPXMediaMusicAlbumArtFileName ) );

                    // Array to read data from
                    CMPXMediaArray* array = CMPXMediaArray::NewL();
                    CleanupStack::PushL( array );

                    // Do we have to use offset or can we use asc/dsc
                    //
                    if( direction == EReadUnknown )
                        {
                        iDbHandler->GetSongsAtOffsetL( array, attrs.Array(), offset, numItems );
                        }
                    else
                        {
                        iDbHandler->GetSongsInBlockL( array, attrs.Array(),
                                                      aCmd.ValueText( KMPXCollectionCommandIdIncOpenLKeyItem ),
                                                      numItems,
                                                      direction );
                        }

                    TInt max( path->Count() );
                    TInt count(0);
                    TInt aryCount( array->Count() );
                    // Update the collection path
                    while( count<numItems && offset<max &&
                           count<aryCount )
                        {
                        TMPXItemId id = array->AtL(count)->ValueTObjectL<TMPXItemId>( KMPXMediaGeneralId );
                        path->Update( offset, id );

                        // Next items
                        offset++;
                        count++;
                        }

                    // Setup the results
                    //
                    results->SetCObjectValueL(KMPXMediaArrayContents, array);
                    results->SetTObjectValueL<TInt>(KMPXMediaArrayCount, array->Count());
                    CleanupStack::PopAndDestroy( array );
                    CleanupStack::PopAndDestroy( &attrs );

                    // Callback with results
                    //
                    results->SetTObjectValueL<TMPXOpenDataBlock>( KMPXCollectionOpenLResultRange, block );
                    iObs->HandleOpen( results, path, KErrNone );
                    CleanupStack::PopAndDestroy( results );
                    break;
                    }
                default:
                    User::Leave(KErrNotSupported);
                    break;
                }
            break;
            }
        default:
            {
            User::Leave(KErrNotSupported);
            break;
            }

        }
    CleanupStack::PopAndDestroy( path );

    MPX_DEBUG1("CMPXDbPlugin::DoIncrementalOpenL -->");
    }

// ----------------------------------------------------------------------------
// Maps a given browse type to a category ID.
// ----------------------------------------------------------------------------
//
TMPXGeneralCategory CMPXDbPlugin::CategoryForBrowseType(
    TMCBrowseType aBrowseType)
    {
    MPX_FUNC("CMPXDbPlugin::CategoryForBrowseType");

    TMPXGeneralCategory cat(EMPXNoCategory);

    switch (aBrowseType)
        {
        case EBrowseAll:
            {
            cat = EMPXSong;
            break;
            }
        case EBrowseArtist:
            {
            cat = EMPXArtist;
            break;
            }
        case EBrowseAlbum:
            {
            cat = EMPXAlbum;
            break;
            }
        case EBrowsePlaylist:
            {
            cat = EMPXPlaylist;
            break;
            }
        case EBrowseGenre:
            {
            cat = EMPXGenre;
            break;
            }
        case EBrowseComposer:
            {
            cat = EMPXComposer;
            break;
            }
#ifdef __ENABLE_PODCAST_IN_MUSIC_MENU
        case EBrowsePodcasts:
            {
            cat = EMPXPodcast;
            break;
            }
#endif
        default:
            {
            // do nothing
            break;
            }
        }

    return cat;
    }

// ----------------------------------------------------------------------------
// Maps a given category ID to a browse type.
// ----------------------------------------------------------------------------
//
TMCBrowseType CMPXDbPlugin::BrowseTypeForCategory(
    TMPXGeneralCategory aCategory)
    {
    MPX_FUNC("CMPXDbPlugin::BrowseTypeForCategory");

    TMCBrowseType browseType(EBrowseComposer);

    switch (aCategory)
        {
        case EMPXSong:
            {
            browseType = EBrowseAll;
            break;
            }
        case EMPXArtist:
            {
            browseType = EBrowseArtist;
            break;
            }
        case EMPXAlbum:
            {
            browseType = EBrowseAlbum;
            break;
            }
        case EMPXPlaylist:
            {
            browseType = EBrowsePlaylist;
            break;
            }
        case EMPXGenre:
            {
            browseType = EBrowseGenre;
            break;
            }
        default:
            {
            // do nothing
            break;
            }
        }

    return browseType;
    }

// ----------------------------------------------------------------------------
// Sets the type, category and title attributes in the specified media instance
// ----------------------------------------------------------------------------
//
void CMPXDbPlugin::SetMediaGeneralAttributesL(
    CMPXMedia& aMedia,
    TMPXGeneralType aType,
    TMPXGeneralCategory aCategory,
    const TDesC& aTitle)
    {
    aMedia.SetTObjectValueL<TMPXGeneralType>(KMPXMediaGeneralType, aType);
    aMedia.SetTObjectValueL<TMPXGeneralCategory>(KMPXMediaGeneralCategory, aCategory);
    aMedia.SetTextValueL(KMPXMediaGeneralTitle, aTitle);
    }

// ----------------------------------------------------------------------------
// Sets the type, category and title attributes in the specified media instance
// ----------------------------------------------------------------------------
//
void CMPXDbPlugin::SetMediaGeneralAttributesL(
    CMPXMedia& aMedia,
    TMPXGeneralType aType,
    TMPXGeneralCategory aCategory,
    TInt aId)
    {
    MPX_FUNC("CMPXDbPlugin::SetMediaGeneralAttributesL");

    HBufC* title = iDbHandler->GetNameMatchingIdL(aId);
    CleanupStack::PushL(title);
    SetMediaGeneralAttributesL(aMedia, aType, aCategory, *title);
    CleanupStack::PopAndDestroy(title);
    }

// ----------------------------------------------------------------------------
// Set the attribute list according to current path
// ----------------------------------------------------------------------------
//
void CMPXDbPlugin::SetAttributesL(
    const CMPXCollectionPath& aPath,
    RArray<TMPXAttribute>& aAttrs,
    RArray<TInt>& aSupportedIds )
    {
    aAttrs.AppendL( TMPXAttribute(KMPXMediaIdGeneral,
        EMPXMediaGeneralId | EMPXMediaGeneralType | EMPXMediaGeneralCategory |
        EMPXMediaGeneralTitle | EMPXMediaGeneralFlags) );

    aSupportedIds.AppendL(KMPXMediaIdContainer);
    aSupportedIds.AppendL(KMPXMediaIdGeneral);

    TInt levels(aPath.Levels());
    if ( 2 == levels )
        {
        // check the browse type
        switch ( aPath.Id(1).iId2 )
            {
            case EBrowseAll:
                {
                aAttrs.AppendL( TMPXAttribute(KMPXMediaIdMusic,
                    EMPXMediaMusicArtist | EMPXMediaMusicAlbumArtFileName ) );
                aSupportedIds.AppendL( KMPXMediaIdMusic );
                break;
                }
            case EBrowseArtist:
                {
                aAttrs.AppendL( TMPXAttribute(KMPXMediaIdGeneral, EMPXMediaGeneralCount) );
                aAttrs.AppendL( TMPXAttribute(KMPXMediaIdMusic,
                                    EMPXMediaMusicAlbumArtFileName ) );
                break;
                }
            case EBrowseAlbum:
                {
                aAttrs.AppendL( TMPXAttribute(KMPXMediaIdMusic,
                    EMPXMediaMusicArtist | EMPXMediaMusicAlbum | EMPXMediaMusicAlbumArtFileName ) );
                aSupportedIds.AppendL( KMPXMediaIdMusic );
                break;
                }
            case EBrowsePlaylist:
                {
                aAttrs.AppendL( TMPXAttribute(KMPXMediaIdGeneral,
                    EMPXMediaGeneralCount | EMPXMediaGeneralDuration ) );
                break;
                }
            case EBrowseGenre:
                {
                aAttrs.AppendL( TMPXAttribute(KMPXMediaIdGeneral, EMPXMediaGeneralCount) );
                break;
                }
            case EBrowseComposer:
                {
                aAttrs.AppendL( TMPXAttribute(KMPXMediaIdGeneral, EMPXMediaGeneralCount) );
                break;
                }
            default:
                {
                User::Leave(KErrArgument);
                }
            }
        }
    else if ( 3 == levels )
        {
        // check the browse type
        switch ( aPath.Id(1).iId2 )
            {
            case EBrowseArtist:
                {
                aAttrs.AppendL( TMPXAttribute(KMPXMediaIdGeneral, EMPXMediaGeneralCount) );
                aAttrs.AppendL( TMPXAttribute(KMPXMediaIdMusic, EMPXMediaMusicAlbumArtFileName ) );
                aSupportedIds.AppendL( KMPXMediaIdMusic );
                break;
                }
            case EBrowseAlbum:
                {

                aAttrs.AppendL( TMPXAttribute(KMPXMediaIdMusic,
                    EMPXMediaMusicArtist | EMPXMediaMusicAlbum | EMPXMediaMusicAlbumArtFileName ) );
                aSupportedIds.AppendL( KMPXMediaIdMusic );
                break;
                }
            case EBrowsePlaylist:
            case EBrowseGenre:
            case EBrowseComposer:
                {
                aAttrs.AppendL( TMPXAttribute(KMPXMediaIdMusic,
//                    EMPXMediaMusicArtist | EMPXMediaMusicAlbumArtFileName ) );
                //added ganes
                    EMPXMediaMusicArtist | EMPXMediaMusicAlbumArtFileName | EMPXMediaMusicAlbum) );
                aSupportedIds.AppendL( KMPXMediaIdMusic );
                break;
                }
            }
        }
    else if ( (4 == levels) && (aPath.Id(1).iId2 == EBrowseArtist) )
        {
        aAttrs.AppendL( TMPXAttribute(KMPXMediaIdMusic,
            EMPXMediaMusicArtist | EMPXMediaMusicAlbum | EMPXMediaMusicAlbumArtFileName ) );
        aSupportedIds.AppendL( KMPXMediaIdMusic );
        }
    }

#ifdef _DEBUG
// ----------------------------------------------------------------------------
// Print change events
// ----------------------------------------------------------------------------
//
void CMPXDbPlugin::PrintMessagesL(
    const CMPXMessage& aMessage)
    {
    MPX_FUNC("CMPXDbPlugin::PrintMessages");

    if (aMessage.IsSupported(KMPXMessageArrayContents))
        {
        const CMPXMessageArray* messageArray =
            aMessage.Value<CMPXMessageArray>(KMPXMessageArrayContents);
        if( !messageArray )
            {
            User::Leave( KErrNoMemory );
            }

        TInt count(messageArray->Count());
        MPX_DEBUG2("%d messages:", count);

        for (TInt i = 0; i < count; ++i)
            {
            PrintMessage(*((*messageArray)[i]));
            }
        }
    else
        {
        PrintMessage(aMessage);
        }
    }

// ----------------------------------------------------------------------------
// Print one change event
// ----------------------------------------------------------------------------
//
void CMPXDbPlugin::PrintMessage(
    const CMPXMessage& aMessage)
    {
    MPX_FUNC("CMPXDbPlugin::PrintMessage");

    if (aMessage.IsSupported(KMPXMessageGeneralId))
        {
        TMPXItemId id = aMessage.ValueTObjectL<TMPXItemId>(KMPXMessageGeneralId);
        MPX_DEBUG3("    message id[0x%x, 0x%x]", id.iId1, id.iId2);
        }

    if (aMessage.IsSupported(KMPXMessageCollectionId))
        {
        TUid uid = aMessage.ValueTObjectL<TUid>(KMPXMessageCollectionId);
        MPX_DEBUG2("    uid [0x%x]", uid.iUid);
        }

    if (aMessage.IsSupported(KMPXMessageChangeEventType))
        {
        MPX_DEBUG2("    change event type [%d]",
            aMessage.ValueTObjectL<TMPXChangeEventType>(KMPXMessageChangeEventType));
        }

    if (aMessage.IsSupported(KMPXMessageMediaGeneralCategory))
        {
        MPX_DEBUG2("    category [%d]",
            aMessage.ValueTObjectL<TMPXGeneralCategory>(KMPXMessageMediaGeneralCategory));
        }

    if (aMessage.IsSupported(KMPXMessageMediaGeneralId))
        {
        TMPXItemId id = aMessage.ValueTObjectL<TMPXItemId>(KMPXMessageMediaGeneralId);
        MPX_DEBUG3("    media id[0x%x, 0x%x]", id.iId1, id.iId2);
        }

    if (aMessage.IsSupported(KMPXMessageMediaDeprecatedId))
        {
        TMPXItemId id = aMessage.ValueTObjectL<TMPXItemId>(KMPXMessageMediaDeprecatedId);
        MPX_DEBUG3("    deprecated id [0x%x, 0x%x]", id.iId1, id.iId2);
        }
    }

#endif// _DEBUG

// End of file