omads/omadsextensions/adapters/mediads/src/mediadsstore.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 31 Aug 2010 15:05:37 +0300
branchRCL_3
changeset 24 8e7494275d3a
permissions -rw-r--r--
Revision: 201033 Kit: 201035

/*
* Copyright (c) 2009 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:  Part of SyncML Data Synchronization Plug In Adapter
*
*/


#include "mediadsstore.h"
#include <mpxmessagegeneraldefs.h>
#include <mpxcollectionmessage.h>

#include "mediadsproviderdefs.h"
#include "mediamanager.h"
#include "cmdemanager.h"
#include "playlistitem.h"
#include "omadsfolderobject.h"
#include "snapshotitem.h"
#include "logger.h"

_LIT8( KFolderMimeType, "application/vnd.omads-folder+xml" );
_LIT8( KFolderMimeVersion, "1.2" );

_LIT8( KPlaylistMimeType, "audio/x-mpegurl");
_LIT8( KPlaylistMimeVersion, "1.0");

_LIT8( KSongMimeType, "application/x-song");
_LIT8( KSongMimeVersion, "1.0");


const TInt KDataBufferSize = 1024;

const TInt KAlbumsOffSet = 0x0000f000;

// -----------------------------------------------------------------------------
// CMediaDsDataStore::CMediaDsDataStore
// C++ default constructor can NOT contain any code, that might leave.
// -----------------------------------------------------------------------------
CMediaDsDataStore::CMediaDsDataStore( RFs& aFs):
    iKey(TKeyArrayFix(_FOFF(TSnapshotItem, ItemId()), ECmpTInt)),
    iFs( aFs )
    { 
    TRACE_FUNC;
    }
  
// -----------------------------------------------------------------------------
// CMediaDsDataStore::ConstructL
// Symbian 2nd phase constructor, can leave.
// -----------------------------------------------------------------------------
void CMediaDsDataStore::ConstructL()
    {
    TRACE_FUNC_ENTRY;
    
    // Item UID sets, used to transfer change info
    iNewItems = new (ELeave) CNSmlDataItemUidSet;
    iDeletedItems = new (ELeave) CNSmlDataItemUidSet;
    iUpdatedItems = new (ELeave) CNSmlDataItemUidSet;
    iMovedItems = new (ELeave) CNSmlDataItemUidSet;
    iSoftDeletedItems = new (ELeave) CNSmlDataItemUidSet;
    
    iHasher = CMD5::NewL();
    
    iMediaManager = CMediaManager::NewL( iFs, this, iKey, *iHasher );
    
    iMdEManager = CMdEManager::NewL( *this );
    
    TRACE_FUNC_EXIT;
    }

// -----------------------------------------------------------------------------
// CMediaDsDataStore::NewLC
// Two-phased constructor.
// -----------------------------------------------------------------------------
CMediaDsDataStore* CMediaDsDataStore::NewLC( RFs& aFs)
    {
    TRACE_FUNC_ENTRY;
    CMediaDsDataStore* self = new (ELeave) CMediaDsDataStore( aFs );
    CleanupStack::PushL( self );
    self->ConstructL();
    TRACE_FUNC_EXIT;
    return self;    
    }

    
// -----------------------------------------------------------------------------
// CMediaDsDataStore::~CMediaDsDataStore
// Destructor
// -----------------------------------------------------------------------------
CMediaDsDataStore::~CMediaDsDataStore()
    {
    TRACE_FUNC_ENTRY;
    
    delete iDataBuffer;
    
    delete iChangeFinder;
    
    delete iNewItems;
    delete iDeletedItems;
    delete iUpdatedItems;
    delete iMovedItems;
    delete iSoftDeletedItems;
    
    delete iMediaManager;
    LOGGER_WRITE("iMediaManager deleted");
    
    delete iMdEManager;
    LOGGER_WRITE("iMdEManager deleted");
    
    delete iHasher;
    LOGGER_WRITE("iHasher deleted");
    // normally iSnapshot is NULL, but if error has occured we need to delete it.
    delete iSnapshot;
    TRACE_FUNC_EXIT;
    }

// -----------------------------------------------------------------------------
// CMediaDsDataStore::DoOpenL
// Opens database. This operation is performed SYNCHRONOUSLY
// -----------------------------------------------------------------------------
void CMediaDsDataStore::DoOpenL( const TDesC& aStoreName,
    MSmlSyncRelationship& aContext, TRequestStatus& aStatus )
    {
    TRACE_FUNC_ENTRY;
    
    iCallerStatus = &aStatus;
    *iCallerStatus = KRequestPending;
    
    if ( iCurrentState != EClosed )
        {
        User::RequestComplete( iCallerStatus, KErrInUse );
        LOGGER_WRITE("CMmsDataStore::DoOpenL failed with KErrInUse.");
        return;
        }
    
    // Create ChangeFinder object
    if ( iChangeFinder )
        {
        delete iChangeFinder;
        iChangeFinder = NULL;
        }
    iChangeFinder = CChangeFinder::NewL( aContext, iKey, iHasHistory, KMediaDataProviderImplUid );
    
    if ( aStoreName.CompareF( KMediaDsRefreshDbName ) == 0 )
        {
        LOGGER_WRITE("Refresh library and open database");
        // just kick off scanner, don't wait ready status
        // Async. func. HandleCollectionMessage is called when ready
        iMediaManager->ScanL();
        
        }
    else if ( aStoreName.CompareF( KMediaDsDbName ) == 0 )
        {
        LOGGER_WRITE("Open database");
        
        if ( !iHasHistory )
            {
            LOGGER_WRITE("No history, scan library");
            // just kick off scanner, don't wait ready status
            // Async. func. HandleCollectionMessage is called when ready
            iMediaManager->ScanL();
            }
        
        }
    else
        {
        LOGGER_WRITE("Unknown database");
        User::Leave( KErrNotSupported );
        }
    
    // Set current snapshot, this will be compared against the old one   
    RegisterSnapshotL();
    
    TRACE_FUNC_EXIT;
    }

// -----------------------------------------------------------------------------
// CMediaDsDataStore::DoCancelRequest
// Not supported, does nothing.
// -----------------------------------------------------------------------------
void CMediaDsDataStore::DoCancelRequest()
    {
    TRACE_FUNC_ENTRY;
    if ( iCurrentState == EOpening )
        {
        LOGGER_WRITE("Cancel Open command");
        iMediaManager->Cancel();
        iMdEManager->Cancel();
        }
    TRACE_FUNC_EXIT;
    }

// -----------------------------------------------------------------------------
// CMediaDsDataStore::DoStoreName
// Returns the name of the DataStore
// -----------------------------------------------------------------------------
const TDesC& CMediaDsDataStore::DoStoreName() const
    {
    TRACE_FUNC;
    return KNullDesC;
    }

// -----------------------------------------------------------------------------
// CMediaDsDataStore::DoBeginTransactionL
// Transactions are not supported.
// -----------------------------------------------------------------------------
void CMediaDsDataStore::DoBeginTransactionL()
    {
    TRACE_FUNC;
    User::Leave( KErrNotSupported );
    }

// -----------------------------------------------------------------------------
// CMediaDsDataStore::DoCommitTransactionL
// Transactions are not supported.
// -----------------------------------------------------------------------------
void CMediaDsDataStore::DoCommitTransactionL( TRequestStatus& /*aStatus*/ )
    {
    TRACE_FUNC;
    User::Leave( KErrNotSupported );
    }

// -----------------------------------------------------------------------------
// CMediaDsDataStore::DoRevertTransaction
// Transactions are not supported.
// -----------------------------------------------------------------------------
void CMediaDsDataStore::DoRevertTransaction( TRequestStatus& aStatus )
    {
    TRACE_FUNC;
    iCallerStatus = &aStatus;
    User::RequestComplete( iCallerStatus, KErrNotSupported );
    }

// -----------------------------------------------------------------------------
// CMediaDsDataStore::DoBeginBatchL
// Batching is not supported.
// -----------------------------------------------------------------------------
void CMediaDsDataStore::DoBeginBatchL()
    {
    TRACE_FUNC;
    User::Leave( KErrNotSupported );
    }

// -----------------------------------------------------------------------------
// CMediaDsDataStore::DoCommitBatchL
// Batching is not supported
// -----------------------------------------------------------------------------
//
void CMediaDsDataStore::DoCommitBatchL( RArray<TInt>& /*aResultArray*/, TRequestStatus& /*aStatus*/ )
    {
    TRACE_FUNC;
    User::Leave( KErrNotSupported );
    }

// -----------------------------------------------------------------------------
// CMediaDsDataStore::DoCancelBatch
// Batching is not supported
// -----------------------------------------------------------------------------
void CMediaDsDataStore::DoCancelBatch()
    {
    TRACE_FUNC;
    }

// -----------------------------------------------------------------------------
// CMediaDsDataStore::DoSetRemoteStoreFormatL
// Not supported
// -----------------------------------------------------------------------------
//
void CMediaDsDataStore::DoSetRemoteStoreFormatL( const CSmlDataStoreFormat& /*aServerDataStoreFormat*/ )
    {
    TRACE_FUNC;
    }

// -----------------------------------------------------------------------------
// CMediaDsDataStore::DoSetRemoteMaxObjectSize
// Not supported
// -----------------------------------------------------------------------------
void CMediaDsDataStore::DoSetRemoteMaxObjectSize( TInt /*aServerMaxObjectSize*/ )
    {
    TRACE_FUNC;
    }

// -----------------------------------------------------------------------------
// CMediaDsDataStore::DoMaxObjectSize
// Reads the maximum MMS Message size from the central repository
// -----------------------------------------------------------------------------
TInt CMediaDsDataStore::DoMaxObjectSize() const
    {
    TRACE_FUNC;
    return 0;
    }

// -----------------------------------------------------------------------------
// CMediaDsDataStore::DoOpenItemL
// Opens item in the DataStore, reads it (either completely or partially) 
// to the temporary buffer where it can be later read to the remote database.
// -----------------------------------------------------------------------------
void CMediaDsDataStore::DoOpenItemL( TSmlDbItemUid aUid, TBool& /*aFieldChange*/, 
    TInt& aSize, TSmlDbItemUid& aParent, TDes8& aMimeType, 
    TDes8& aMimeVer, TRequestStatus& aStatus )
    {
    TRACE_FUNC_ENTRY;

    LOGGER_WRITE_1( "Opening item %d.", aUid );
    
    // Store these for later use
    iCallerStatus = &aStatus;
    *iCallerStatus = KRequestPending;
    
    iReadPosition=0;
    
    // Check that we're in a proper state
    if ( iCurrentState != EOpenAndWaiting )
        {
        LOGGER_WRITE_1( "CMediaDsDataStore::DoOpenItemL, invalid state %d.", iCurrentState );
        User::RequestComplete( iCallerStatus, KErrNotReady );
        return;
        }
    
    if ( !iDataBuffer )
        {
        iDataBuffer = CBufFlat::NewL( KDataBufferSize );
        }
    iDataBuffer->Reset();

    
    if ( aUid <= KLastFolderId )
        {
        COMADSFolderObject* folderObject = COMADSFolderObject::NewLC();
        
        switch ( aUid )
            {
            case KAllSongsFolderId:
                folderObject->SetName( KAllSongs );
                break;
            case KPlaylistsFolderId:
                folderObject->SetName( KPlaylists );
                break;
            case KAlbumsFolderId:
                folderObject->SetName( KAlbums );
                break;
            default:
                User::Leave( KErrNotFound );
                break;
            }
        folderObject->ExportFolderXmlL( *iDataBuffer );
        CleanupStack::PopAndDestroy( folderObject );
        aMimeType.Copy( KFolderMimeType );
        aMimeVer.Copy( KFolderMimeVersion );
        aParent = KErrNotFound;
        }
    else
        {
        CSongItem* song = CSongItem::NewLC();
        LOGGER_WRITE("Try to read song");
        TRAPD( err, iMediaManager->GetSongL( aUid, *song ));
        if ( !err )
            {
            RBufWriteStream stream( *iDataBuffer );
            CleanupClosePushL( stream );
            song->ExportL( stream );
            CleanupStack::PopAndDestroy( &stream );
            CleanupStack::PopAndDestroy( song );
            
            aMimeType.Copy( KSongMimeType );
            aMimeVer.Copy( KSongMimeVersion );
            aParent = KAllSongsFolderId;
            }
        else // could not read song, maybe it is playlist
            {
            CleanupStack::PopAndDestroy( song );
            CPlaylistItem* playList = CPlaylistItem::NewLC();
            LOGGER_WRITE("Try to read playlist");
            TRAP(err, iMediaManager->GetPlayListL( aUid, *playList ));
            if ( !err )
                {
                RBufWriteStream stream( *iDataBuffer );
                CleanupClosePushL( stream );
                
                playList->ExportL( stream );
                CleanupStack::PopAndDestroy( &stream );
                CleanupStack::PopAndDestroy( playList );
                
                aMimeType.Copy( KPlaylistMimeType );
                aMimeVer.Copy( KPlaylistMimeVersion );
                aParent = KPlaylistsFolderId;
                }
            else
                {
                CleanupStack::PopAndDestroy( playList );
                LOGGER_WRITE("Try to read album");
                // Could not read song, maybe it's a Album
                const CPlaylistItem& album = iMdEManager->AlbumL( MapSyncIdToAlbumId(aUid) );
                RBufWriteStream stream( *iDataBuffer );
                CleanupClosePushL( stream );
                
                album.ExportL( stream );
                CleanupStack::PopAndDestroy( &stream );
                
                aMimeType.Copy( KPlaylistMimeType );
                aMimeVer.Copy( KPlaylistMimeVersion );
                aParent = KAlbumsFolderId;
                }
            }
        
        }
    
    aSize = iDataBuffer->Size();
    
    LOGGER_WRITE_1("aSize: %d", aSize);
    
    // Signal we're complete
    User::RequestComplete( iCallerStatus, KErrNone ); 

    TRACE_FUNC_EXIT;
    }

// -----------------------------------------------------------------------------
// CMediaDsDataStore::DoCreateItemL
// Create new item to the message store.
// Return the id number of the newly created item
// -----------------------------------------------------------------------------
void CMediaDsDataStore::DoCreateItemL( TSmlDbItemUid& aUid, TInt aSize, TSmlDbItemUid aParent, 
    const TDesC8& aMimeType, const TDesC8& /*aMimeVer*/, TRequestStatus& aStatus )
    {
    TRACE_FUNC_ENTRY;
    LOGGER_WRITE_1( "Parent folder: %d.", aParent );
    
    // Store some variables for further use
    iCallerStatus = &aStatus;
    *iCallerStatus = KRequestPending;
    
    // Ensure that we're in proper state
    if ( iCurrentState != EOpenAndWaiting )
        {
        LOGGER_WRITE_1( "Invalid state %d.", iCurrentState );
        }
    
    iWrittenDataLength = 0;
    iCreatedUid = &aUid;
    LOGGER_WRITE8_1( "aMimeType: %S", &aMimeType );
    
    if ( aMimeType.Compare( KPlaylistMimeType() ) == 0 )
        {
        LOGGER_WRITE("Add Playlist");
        iCurrentState = ECreatePlaylist;
        }
    else if ( aMimeType.Compare( KSongMimeType() ) == 0 )
        {
        LOGGER_WRITE("Add Song not supported");
        User::Leave( KErrNotSupported );
        }
    else
        {
        User::RequestComplete( iCallerStatus, KErrNotSupported );
        LOGGER_WRITE("Bad MIME type");
        return;
        }
    
    if ( iDataBuffer )
        {
        iDataBuffer->ResizeL( aSize );
        }
    else
        {
        iDataBuffer = CBufFlat::NewL( KDataBufferSize );
        iDataBuffer->ResizeL( aSize );
        }
    LOGGER_WRITE_1("iDataBuffer->Size: %d", iDataBuffer->Size());
    
    LOGGER_WRITE_1("aSize: %d", aSize);
    iParentId = aParent;
    
    // Signal we're complete
    User::RequestComplete( iCallerStatus, KErrNone );
    
    TRACE_FUNC_EXIT;
    }

// -----------------------------------------------------------------------------
// CMediaDsDataStore::DoReplaceItemL
// Begin the replace operation, ensure that the item really exists
// -----------------------------------------------------------------------------
void CMediaDsDataStore::DoReplaceItemL( TSmlDbItemUid aUid, TInt aSize, TSmlDbItemUid aParent, 
    TBool /*aFieldChange*/, TRequestStatus& aStatus )
    {
    TRACE_FUNC_ENTRY;
    LOGGER_WRITE_1("Replacing item %d.", aUid);
    LOGGER_WRITE_1("Parent folder: %d.", aParent);
    
    // Store some variables for further use
    iCallerStatus = &aStatus;
    *iCallerStatus = KRequestPending;
    
    // Ensure proper state
    if ( iCurrentState != EOpenAndWaiting )
        {
        LOGGER_WRITE_1("Invalid state %d.", iCurrentState);
        }
    
    iCurrentState = EReplace;
    
    iParentId = aParent;
    iCurrentId = aUid;
    
    if ( iDataBuffer )
        {
        iDataBuffer->ResizeL( aSize );
        }
    else
        {
        iDataBuffer = CBufFlat::NewL( KDataBufferSize );
        iDataBuffer->ResizeL( aSize );
        }
    
    // Signal we're complete
    User::RequestComplete( iCallerStatus, KErrNone );
    
    TRACE_FUNC_EXIT;
    }

// -----------------------------------------------------------------------------
// CMediaDsDataStore::DoReadItemL
// Read specified amount of data from the temporary buffer
// -----------------------------------------------------------------------------
void CMediaDsDataStore::DoReadItemL( TDes8& aBuffer )
    {
    TRACE_FUNC_ENTRY;
    // Thiw is how much data there is left in the buffer    
    TInt left = iDataBuffer->Size() - iReadPosition;
    
    if ( left > 0 )
        {
        // This is how much there's space in the destination buffer
        TInt destSize = aBuffer.MaxSize();
        
        // This is how much we can read
        TInt toRead = destSize < left ? destSize : left;
        
        // Read the data from the buffer, then update the position      
        iDataBuffer->Read( iReadPosition, aBuffer, toRead );
        iReadPosition += toRead;
        }
    else
        {
        LOGGER_WRITE( "No data to read" );
        User::Leave( KErrEof );
        }   
    TRACE_FUNC_EXIT;
    }

// -----------------------------------------------------------------------------
// CMediaDsDataStore::DoWriteItemL
// Write specified amount of data to the temporary buffer
// -----------------------------------------------------------------------------
void CMediaDsDataStore::DoWriteItemL( const TDesC8& aData )
    {
    TRACE_FUNC_ENTRY;
    
    iDataBuffer->Write( iWrittenDataLength, aData );
    iWrittenDataLength += aData.Size();
    
    TRACE_FUNC_EXIT;
    }

// -----------------------------------------------------------------------------
// CMediaDsDataStore::DoCommitItemL
// Commits item from temporary buffer to the message store
// -----------------------------------------------------------------------------
void CMediaDsDataStore::DoCommitItemL( TRequestStatus& aStatus )
    {
    TRACE_FUNC_ENTRY;
    
    // Store some variables
    iCallerStatus = &aStatus;
    *iCallerStatus = KRequestPending;
    
    iDataBuffer->Compress();
    
    // Read the playlist item
    CPlaylistItem* newItem = CPlaylistItem::NewLC();
    
    const TUint8* ptr8 = iDataBuffer->Ptr(0).Ptr();
    const TUint16* ptr16 = reinterpret_cast<const TUint16*>( ptr8 );
    TPtrC dataPtr;
    dataPtr.Set( ptr16, iDataBuffer->Size()/2 );
    newItem->ImportL( dataPtr );
    
    iDataBuffer->Reset();
    
#ifdef _DEBUG
    LOGGER_WRITE_1("Name: %S", &newItem->Title());
    LOGGER_WRITE_1("Items count: %d", newItem->ItemCount());
    for ( TInt i=0; i<newItem->ItemCount(); i++ )
        {
        TPtrC16 ptr = newItem->ItemAt(i);
        LOGGER_WRITE_1("item: %S", &ptr);
        }
#endif
    
    
    TInt error(KErrNone);
    if ( iCurrentState == ECreatePlaylist )
        {
        if ( iParentId == KPlaylistsFolderId )
            {
            iMediaManager->CreateNewPlaylistL( *iCreatedUid, *newItem );
            }
        else if ( iParentId == KAlbumsFolderId )
            {
            iMdEManager->CreateAlbumL( *newItem );
            *iCreatedUid = MapAlbumIdToSyncId( newItem->Id() );
            }
        else
            {
            LOGGER_WRITE("Not supported");
            User::Leave( KErrNotSupported);
            }
        
        // Inform ChangeFinder of the added item
        TSnapshotItem snapshotItem( *iCreatedUid );
        snapshotItem.SetParentId( iParentId );
        snapshotItem.SetItemHash( *newItem, *iHasher );
        iChangeFinder->ItemAddedL( snapshotItem );
        
        }
    else if ( iCurrentState == EReplace )
        {
        if ( iParentId == KPlaylistsFolderId )
            {
            iMediaManager->ReplacePlaylistL( iCurrentId, *newItem );
            }
        else if ( iParentId == KAlbumsFolderId )
            {
            iItemInReplacement.SetItemId( iCurrentId );
            iItemInReplacement.SetParentId( iParentId );
            iItemInReplacement.SetItemHash( *newItem, *iHasher );
            // Async function, calls AlbumReplaced when completed
            iMdEManager->ReplaceAlbumL( MapSyncIdToAlbumId(iCurrentId), *newItem );
            
            CleanupStack::PopAndDestroy( newItem );
            return;
            }
        else
            {
            LOGGER_WRITE("Not supported");
            User::Leave( KErrNotSupported);
            }
        
        // Inform ChangeFinder of the replaced item
        TSnapshotItem snapshotItem( iCurrentId );
        snapshotItem.SetParentId( iParentId );
        snapshotItem.SetItemHash( *newItem, *iHasher );
        iChangeFinder->ItemUpdatedL( snapshotItem );
        }
    else
        {
        LOGGER_WRITE_1("Wrong state: %d", iCurrentState);
        User::Leave( KErrNotSupported );
        }
    CleanupStack::PopAndDestroy( newItem );
    
    
    
    LOGGER_WRITE_1("error: %d", error);
    // We'll be waiting for next event, signal we're done
    iCurrentState = EOpenAndWaiting;
    User::RequestComplete( iCallerStatus, error );
    
    TRACE_FUNC_EXIT;
    }

// -----------------------------------------------------------------------------
// CMediaDsDataStore::DoCloseItem
// Closes open item in the data store
// -----------------------------------------------------------------------------
void CMediaDsDataStore::DoCloseItem()
    {
    TRACE_FUNC_ENTRY;
    if ( iDataBuffer )
        {
        iDataBuffer->Reset();
        }
    iCurrentState = EOpenAndWaiting;
    iReadPosition = 0;
    TRACE_FUNC_EXIT;
    }

// -----------------------------------------------------------------------------
// CMediaDsDataStore::DoMoveItemL
// Moves item from one folder to another in the message store
// -----------------------------------------------------------------------------
void CMediaDsDataStore::DoMoveItemL( TSmlDbItemUid /*aUid*/,
    TSmlDbItemUid /*aNewParent*/, TRequestStatus& /*aStatus*/ )
    {
    TRACE_FUNC;
    User::Leave( KErrNotSupported );
    }

// -----------------------------------------------------------------------------
// CMediaDsDataStore::DoDeleteItemL
// Removes item from the message store
// -----------------------------------------------------------------------------
void CMediaDsDataStore::DoDeleteItemL( TSmlDbItemUid aUid, TRequestStatus& aStatus  )
    {
    TRACE_FUNC_ENTRY;
    LOGGER_WRITE_1("Deleting item %d.", aUid);
    
    // Store some variables for further use
    iCallerStatus = &aStatus;
    *iCallerStatus = KRequestPending;
    
    TInt error(KErrNone);
    
    // Check that we're in proper state
    if ( iCurrentState != EOpenAndWaiting ) 
        {
        LOGGER_WRITE_1("CMmsDataStore::DoDeleteItemL, invalid state %d.", iCurrentState);        
        }
    
    TRAP( error,  iMediaManager->DeletePlaylistL( aUid ) );
    if ( error )
        {
        error = KErrNone;
        iMdEManager->DeleteAlbumL( MapSyncIdToAlbumId( aUid ) );
        }
    
    if ( !error )
        {
        // Inform ChangeFinder of the deleted item
        TSnapshotItem snapshotItem( aUid );
        iChangeFinder->ItemDeletedL( snapshotItem );
        }
    
    LOGGER_WRITE_1("complete error: %d", error);
    // Signal we're done
    User::RequestComplete( iCallerStatus, error );
    TRACE_FUNC_EXIT;
    }

// -----------------------------------------------------------------------------
// CMediaDsDataStore::DoSoftDeleteItemL
// Soft delete isn't supported.
// -----------------------------------------------------------------------------
void CMediaDsDataStore::DoSoftDeleteItemL( TSmlDbItemUid /*aUid*/, TRequestStatus& aStatus )
    {
    TRACE_FUNC_ENTRY;
    
    // Store some variables for further use
    iCallerStatus = &aStatus;
    *iCallerStatus = KRequestPending;

    // Signal we're done
    User::RequestComplete( iCallerStatus, KErrNotSupported );
    
    TRACE_FUNC_EXIT;
    }

// -----------------------------------------------------------------------------
// CMediaDsDataStore::DoDeleteAllItemsL
// Deletes all items in the standard folders of message store
// -----------------------------------------------------------------------------
void CMediaDsDataStore::DoDeleteAllItemsL( TRequestStatus& aStatus )
    {
    TRACE_FUNC_ENTRY;
    
    // Store some variables for further use 
    iCallerStatus = &aStatus;
    *iCallerStatus = KRequestPending;
    
    User::RequestComplete( iCallerStatus, KErrNotSupported );
    
    TRACE_FUNC_EXIT;
    }

// -----------------------------------------------------------------------------
// CMediaDsDataStore::DoHasSyncHistory
// This method returns ETrue if Data Store has history information. 
// Slow-sync will be used if Data Store does not have history information.
// -----------------------------------------------------------------------------
TBool CMediaDsDataStore::DoHasSyncHistory() const
    {
    TRACE_FUNC_RET( (TInt)iHasHistory );      
    
    // iHasHistory is initialized in DoOpenL method
    return iHasHistory;
    }

// -----------------------------------------------------------------------------
// CMediaDsDataStore::DoAddedItems
// This method returns UIDs of added items. Those items are added after previous
// synchronization with current synchronization relationship. 
// -----------------------------------------------------------------------------
const MSmlDataItemUidSet& CMediaDsDataStore::DoAddedItems() const
    {
    TRACE_FUNC;
    
    // Ensure that we're in a proper state
    if ( iCurrentState != EOpenAndWaiting )
        {
        LOGGER_WRITE_1("CMmsDataStore::DoAddedItems, invalid state %d.", iCurrentState);
        }
    
    TInt error(KErrNone);

    // Clear new-items array
    iNewItems->Reset();

    // Set current snapshot, this will be compared against the old one      
    // Search for new items
    TRAP( error, iChangeFinder->FindNewItemsL(*iNewItems) )
    if ( error != KErrNone )
        {
        LOGGER_WRITE_1("CMmsDataStore::DoAddedItems, iChangeFinder->FindNewItemsL leaved with %d.", error);
        }
    
    LOGGER_WRITE_1("New item count: %d.", iNewItems->ItemCount());
    
    return *iNewItems;
    }

// -----------------------------------------------------------------------------
// CMediaDsDataStore::DoDeletedItems
//
// -----------------------------------------------------------------------------
const MSmlDataItemUidSet& CMediaDsDataStore::DoDeletedItems() const
    {
    TRACE_FUNC;
    
    // Ensure that we're in a proper state
    if ( iCurrentState != EOpenAndWaiting )
        {
        LOGGER_WRITE_1("CMmsDataStore::DoDeletedItems, invalid state %d.", iCurrentState);
        }
    
    TInt error(KErrNone);
    
    // Clear deleted-items array
    iDeletedItems->Reset();
    
    // Search for deleted items
    TRAP( error, iChangeFinder->FindDeletedItemsL( *iDeletedItems ) );
    if ( error != KErrNone )
        {
        LOGGER_WRITE_1("CMmsDataStore::DoDeletedItems, iChangeFinder->FindDeletedItemsL leaved with %d.", error);
        }           
    
    LOGGER_WRITE_1("Deleted item count: %d.", iDeletedItems->ItemCount());
    return *iDeletedItems;
    }

// -----------------------------------------------------------------------------
// CMediaDsDataStore::DoSoftDeletedItems
// Not directly supported, equals to "hard" delete
// -----------------------------------------------------------------------------
const MSmlDataItemUidSet& CMediaDsDataStore::DoSoftDeletedItems() const
    {
    TRACE_FUNC;

    iSoftDeletedItems->Reset();
    return *iSoftDeletedItems;
    }

// -----------------------------------------------------------------------------
// CMediaDsDataStore::DoModifiedItems
// Finds all modified items in the data store
// -----------------------------------------------------------------------------
const MSmlDataItemUidSet& CMediaDsDataStore::DoModifiedItems() const
    {
    TRACE_FUNC;
    
    // Ensure that we're in a proper state
    if ( iCurrentState != EOpenAndWaiting )
        {
        LOGGER_WRITE_1("CMmsDataStore::DoModifiedItems, invalid state %d.", iCurrentState);
        }
    
    TInt error(KErrNone);
    
    // Clear updated-items array
    iUpdatedItems->Reset();
    
    // Search for updated items
    TRAP( error, iChangeFinder->FindChangedItemsL( *iUpdatedItems ) )
    if ( error != KErrNone )
        {
        LOGGER_WRITE_1("CMmsDataStore::DoModifiedItems, iChangeFinder->FindChangedItemsL leaved with %d.", error);
        }
    
    LOGGER_WRITE_1("Modified item count: %d.", iUpdatedItems->ItemCount()); 
    return *iUpdatedItems;
    }

// -----------------------------------------------------------------------------
// CMediaDsDataStore::DoMovedItems
// Finds all moved items in the data store
// -----------------------------------------------------------------------------
const MSmlDataItemUidSet& CMediaDsDataStore::DoMovedItems() const
    {
    TRACE_FUNC;
    // return empty array
    return *iMovedItems;    
    }

// -----------------------------------------------------------------------------
// CMediaDsDataStore::DoResetChangeInfoL
// Resets change history in the data store. All content is considered
// new in the data store point of view.
// -----------------------------------------------------------------------------
void CMediaDsDataStore::DoResetChangeInfoL( TRequestStatus& aStatus )
    {
    TRACE_FUNC_ENTRY;
    
    iCallerStatus = &aStatus;
    *iCallerStatus = KRequestPending;
    
    // Check that we're in proper state
    if ( iCurrentState != EOpenAndWaiting ) 
        {
        LOGGER_WRITE_1("CMmsDataStore::DoResetChangeInfoL, invalid state %d.", iCurrentState);
        }   
            
    // Reset change info in ChangeFinder
    iChangeFinder->ResetL();
    iHasHistory = EFalse;
    
    // Signal we're done
    User::RequestComplete( iCallerStatus, KErrNone ); 
    
    TRACE_FUNC_EXIT;
    }
        
// -----------------------------------------------------------------------------
// CMediaDsDataStore::DoCommitChangeInfoL
// Commits change info. These items are no longer reported, when change
// information is being queried.
// -----------------------------------------------------------------------------
void CMediaDsDataStore::DoCommitChangeInfoL( TRequestStatus& aStatus, const MSmlDataItemUidSet& aItems )
    {
    TRACE_FUNC_ENTRY;
    
    iCallerStatus = &aStatus;
    *iCallerStatus = KRequestPending;
    
    // Ensure that we're in a proper state
    if ( iCurrentState != EOpenAndWaiting ) 
        {
        LOGGER_WRITE_1("CMmsDataStore::DoCommitChangeInfoL, invalid state %d.", iCurrentState);
        }

    // Notify ChangeFinder
    iChangeFinder->CommitChangesL(aItems);
    iHasHistory = ETrue;
        
    // Signal we're done
    User::RequestComplete(iCallerStatus, KErrNone);
        
    TRACE_FUNC_EXIT;
    }
        
    
// -----------------------------------------------------------------------------
// CMediaDsDataStore::DoCommitChangeInfoL
// Commits change info. There is no more nothing to report when change
// information is being queried. 
// -----------------------------------------------------------------------------
void CMediaDsDataStore::DoCommitChangeInfoL(TRequestStatus& aStatus)
    {
    TRACE_FUNC_ENTRY;
    
    iCallerStatus = &aStatus;
    *iCallerStatus = KRequestPending;
    
    // Ensure that we're in a proper state
    if ( iCurrentState != EOpenAndWaiting ) 
        {
        LOGGER_WRITE_1("CMmsDataStore::DoCommitChangeInfoL, invalid state %d.", iCurrentState);
        }
    
    // Notify ChangeFinder
    iChangeFinder->CommitChangesL();
    iHasHistory = ETrue;
        
    // Signal we're done
    User::RequestComplete( iCallerStatus, KErrNone );
    
    TRACE_FUNC_EXIT;
    }


void CMediaDsDataStore::HandleCollectionMessage(CMPXMessage* /*aMsg*/, TInt /*aErr*/) 
    {
    TRACE_FUNC;
    }

void CMediaDsDataStore::HandleOpenL(const CMPXMedia& /*aEntries*/,
        TInt /*aIndex*/,TBool /*aComplete*/,TInt /*aError*/)
    {
    TRACE_FUNC;
    }

void CMediaDsDataStore::HandleOpenL(const CMPXCollectionPlaylist& /*aPlaylist*/,
        TInt /*aError*/)
    {
    TRACE_FUNC;
    }
    
void CMediaDsDataStore::HandleCommandComplete(CMPXCommand* /*aCommandResult*/, 
         TInt /*aError*/)
    {
    TRACE_FUNC;
    }

void CMediaDsDataStore::HandleCollectionMediaL(const CMPXMedia& /*aMedia*/, 
        TInt /*aError*/)
    {
    TRACE_FUNC;
    }

void CMediaDsDataStore::AlbumsReaded( TInt aError )
    {
    TRACE_FUNC_ENTRY;
    iMdEManagerReady = ETrue;
    LOGGER_WRITE_1("aError: %d", aError );
    
    if ( aError )
        {
        iError = aError;
        }
    
    FinalizeOpenStore();
    
    TRACE_FUNC_EXIT;
    }

void CMediaDsDataStore::AlbumReplaced( TInt aError )
    {
    TRACE_FUNC_ENTRY;
    LOGGER_WRITE_1("aError: %d", aError);
    if ( !aError )
        {
        // Inform ChangeFinder of the replaced item
        iChangeFinder->ItemUpdatedL( iItemInReplacement );
        }
    
    iCurrentState = EOpenAndWaiting;
    User::RequestComplete( iCallerStatus, aError );
    TRACE_FUNC_EXIT;
    }

// -----------------------------------------------------------------------------
// CMediaDsDataStore::RegisterSnapshotL
// Sets Changefinder to compare against current message store content
// -----------------------------------------------------------------------------
void CMediaDsDataStore::RegisterSnapshotL()
    {
    TRACE_FUNC_ENTRY;
    if ( iSnapshot )
        {
        delete iSnapshot;
        iSnapshot = NULL;
        }
    iSnapshot = new (ELeave) CSnapshotArray( KSnapshotGranularity );
    RegisterFoldersL( *iSnapshot );
    iMediaManager->SetSnapshot( iSnapshot );
    
    iCurrentState = EOpening;
    TInt err = iMediaManager->RegisterAllPlayLists();
    if ( err )
        {
        LOGGER_WRITE_1("Could not start, err: %d", err);
        iCurrentState = EClosed;
        User::RequestComplete( iCallerStatus, err );
        }
    else
        {
        iMdEManager->GetAlbumsL();
        }

    
    TRACE_FUNC_EXIT;
    }

void CMediaDsDataStore::RegisterAllPlayListsCompleted( TInt aError )
    {
    TRACE_FUNC_ENTRY;
    if ( !aError )
        {
        TInt err = iMediaManager->RegisterAllSongs();
        if ( err )
            {
            LOGGER_WRITE_1("Could not start, err: %d", err);
            iMediaManagerReady = ETrue;
            iError = err;
            }
        }
    else
        {
        // Error happened or cancelled.
        iMediaManagerReady = ETrue;
        iError = aError;
        }
    
    FinalizeOpenStore();
    TRACE_FUNC_EXIT;
    }

void CMediaDsDataStore::RegisterAllSongsCompleted( TInt aError )
    {
    TRACE_FUNC_ENTRY;
    iMediaManagerReady = ETrue;
    if ( aError )
        {
        // Error happened or cancelled, save error code
        iError = aError;
        }
    
    FinalizeOpenStore();
    
    TRACE_FUNC_EXIT;
    }

// -----------------------------------------------------------------------------
// CMediaDsDataStore::RegisterFoldersL
// 
// -----------------------------------------------------------------------------
void CMediaDsDataStore::RegisterFoldersL( CSnapshotArray& aItemArray )
    {
    TRACE_FUNC_ENTRY;
    
    TKeyArrayFix key( iKey );
    TSnapshotItem folder;
    folder.SetItemId( KAllSongsFolderId );
    folder.SetItemHash( KAllSongs, *iHasher );
    aItemArray.InsertIsqL( folder, key );
    
    folder.SetItemId( KPlaylistsFolderId );
    folder.SetItemHash( KPlaylists, *iHasher );
    aItemArray.InsertIsqL( folder, key );
    
    folder.SetItemId( KAlbumsFolderId );
    folder.SetItemHash( KAlbums, *iHasher );
    aItemArray.InsertIsqL( folder, key );
    TRACE_FUNC_EXIT;
    }

void CMediaDsDataStore::FinalizeOpenStore()
    {
    TRACE_FUNC_ENTRY;
    // Signal client if all ready
    if ( iMediaManagerReady && iMdEManagerReady )
        {
        if ( !iError )
            {
            RPointerArray<CPlaylistItem> albums = iMdEManager->AlbumsArray();
            TKeyArrayFix key( iKey );
            LOGGER_WRITE("Album snapshots:")
            for (TInt i=0; i<albums.Count(); i++)
                {
                TSnapshotItem playlistItem( MapAlbumIdToSyncId( albums[i]->Id() ) );
                playlistItem.SetItemHash( *albums[i], *iHasher );
                playlistItem.SetParentId( KAlbumsFolderId );
                TRAP(iError, iSnapshot->InsertIsqL( playlistItem, key ));
                if ( iError )
                    {
                    LOGGER_WRITE_1("iSnapshot->InsertIsqL err: %d", iError);
                    iError = KErrGeneral;
                    }
                }
            
            if ( !iError )
                {
                // Set new snapshot to compare against
                iChangeFinder->SetNewSnapshot(iSnapshot);
                
                // Changefinder takes ownership of the snapshot
                iSnapshot = NULL;
                iCurrentState = EOpenAndWaiting;
                }
            }
        
        if ( iError )
            {
            iCurrentState = EClosed;
            }
        
        LOGGER_WRITE_1("Signal client with %d", iError);
        User::RequestComplete( iCallerStatus, iError );
        }
    TRACE_FUNC_EXIT;
    }

inline TInt CMediaDsDataStore::MapSyncIdToAlbumId( TSmlDbItemUid aSyncId )
    {
    return aSyncId - KAlbumsOffSet;
    }

inline TSmlDbItemUid CMediaDsDataStore::MapAlbumIdToSyncId( TInt aAlbumId )
    {
    return KAlbumsOffSet + aAlbumId;
    }