/*
* Copyright (c) 2007 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:  This class is responsible for managing all database access
*                databases.
*
*/


// INCLUDE FILES

#include <sqldb.h>
#include <badesca.h>
#include <f32file.h>
// PREQ2536 the files sqlrowsetutil.h and sqlrowsetutil.cpp has been removed
//#ifdef __WINSCW__    
//#include <sqlrowsetutil.h>
//#endif
#include <sysutil.h>
#ifdef __RAMDISK_PERF_ENABLE
#include <centralrepository.h>
#include <bautils.h>  
#include <mpxinternalcrkeys.h>
#endif //__RAMDISK_PERF_ENABLE

#include <mpxlog.h>

#include "mpxdbcommondef.h"
#include "mpxtable.h"
#include "mpxdbmanager.h"

// CONSTANTS

// Version of   Database
const   TInt KMPXDbVersion[] = {6,0,0};

_LIT8( KMCSqlConfig, "cache_size=1024; page_size=16384; " );

_LIT(KSecureFilePath,   "%S[%x]%S");
_LIT(KRootDrive, "C:");
_LIT(KAliasName, "%1SDrive");
_LIT(KBeginTransaction, "BEGIN TRANSACTION");
_LIT(KCommitTransaction, "COMMIT TRANSACTION");
_LIT(KRollbackTransaction, "ROLLBACK TRANSACTION");
_LIT(KOrderByToken, "ORDER BY");
_LIT(KDBNameToken, ":dbname");
_LIT(KPlDBNameToken, ":pldbname");
_LIT(KUnionAllToken, " UNION ALL ");
_LIT(KSelectToken, "SELECT");

//for database deletion
_LIT( KDBFilePath, "\\private\\10281e17\\" );
_LIT( KDBFilePattern, "*.db*" );    

#ifdef _DEBUG
_LIT(KTableQuery, "SELECT * FROM %S");
_LIT(KAttachedTableQuery, "SELECT * FROM :dbname.%S");
_LIT(KFindAllCDriveTablesQuery, "SELECT name FROM   sqlite_master WHERE type = 'table' ORDER BY name");
_LIT(KFindAllAttachedTablesQuery, "SELECT name FROM :dbname.sqlite_master WHERE type = 'table' ORDER BY name");
_LIT(KNameColumn, "name");
#endif

const TInt KMaxLogQuery = 248;
const TInt KBufIncrement = 10;

#ifdef __RAMDISK_PERF_ENABLE
_LIT(KSecurePath,   "[%x]%S");
_LIT(KRAMAliasName, "%S");
_LIT( KDummyDbFile, "%c:\\private\\10281e17\\dummydb.dat" );
const TInt64 KMPMegaByte = 1048576;
const TInt64 KMPEstimatedSongInBytes = KMPMegaByte * 2; 
const TInt KMPEstimatedSizePerDBEntry = 3000; // worst scenario, can be lower if needed
const TInt KMPMinimumRAMSizeToRun = 6 * KMPMegaByte; 
// if RAM is lower than 5MB, doesn't seem enough for SQL as well.
// so we set this number to move back DBs before being kicked out

#endif //__RAMDISK_PERF_ENABLE

// Used to suppress overflow when appending formatted text to a buffer.
class TOverflowHandle :
    public TDesOverflow
    {
    public:
        TOverflowHandle() :
            iFlag(EFalse)
            {
            }

        virtual void Overflow(TDes& /* aDes */)
            {
            iFlag = ETrue;
            return;
            }

        TBool GetOverflowFlag()
            {
            TBool flag(iFlag);
            iFlag = EFalse;
            return flag;
            }
    protected:
        TBool iFlag;
    };

// ============================ MEMBER FUNCTIONS ==============================

// ----------------------------------------------------------------------------
// Constructor
// ----------------------------------------------------------------------------
//
EXPORT_C CMPXDbManager::CMPXDbManager(
    RFs& aFs) :
    iFs(aFs), 
    iRAMDiskPerfEnabled(EFalse),
    iMaximumAllowedRAMDiskSpaceToCopy(0),
    iRAMInUse(EFalse)
    {
    MPX_FUNC("CMPXDbManager::CMPXDbManager");
    }

// ----------------------------------------------------------------------------
// Second phase constructor.
// ----------------------------------------------------------------------------
//
EXPORT_C void CMPXDbManager::ConstructL(
    const TFileName& aDatabaseFile)
    {
    MPX_FUNC("CMPXDbManager::ConstructL");
    iDbFile = aDatabaseFile.AllocL();
    
#ifdef __RAMDISK_PERF_ENABLE
    TInt flags( 0 );
    CRepository* repository = CRepository::NewLC( KCRUidMPXMPFeatures );
    User::LeaveIfError( repository->Get( KMPXMPLocalVariation, flags ));
    MPX_DEBUG2("CMPXDbManager::ConstructL KMPXMPLocalVariation %d", flags);        
    iRAMDiskPerfEnabled = static_cast<TBool>( flags & KMPXEnableRAMDisk );
    
    TInt temp;
    User::LeaveIfError( repository->Get( KMAXAllowedDiskSpaceToCopy, temp) );
    iMaximumAllowedRAMDiskSpaceToCopy = temp * KMPMegaByte;
    CleanupStack::PopAndDestroy(repository);
            
    if ( iRAMDiskPerfEnabled )
        {
        MPX_DEBUG1("CMPXDbManager::ConstructL RAMDisk performance is enabled.");
        MPX_DEBUG2("CMPXDbManager::ConstructL RAMDisk iMaximumAllowedRAMDiskSpaceToCopy=%Lu", iMaximumAllowedRAMDiskSpaceToCopy);
        if ( GetRAMDiskPath() != KErrNone )
            {
            // Error finding ram drive, disable ram disk
            iRAMDiskPerfEnabled = EFalse;
            }
        }
    else
        {
        MPX_DEBUG2("CMPXDbManager::ConstructL RAMDisk performance is NOT enabled flag=%d", flags);
        MPX_DEBUG2("CMPXDbManager::ConstructL RAMDisk iMaximumAllowedRAMDiskSpaceToCopy=%Lu", iMaximumAllowedRAMDiskSpaceToCopy);
        }
#endif //__RAMDISK_PERF_ENABLE
    }

// ----------------------------------------------------------------------------
// Destructor
// ----------------------------------------------------------------------------
//
EXPORT_C CMPXDbManager::~CMPXDbManager()
    {
    MPX_FUNC("CMPXDbManager::~CMPXDbManager");

    // Close the state array
    iPreparedStatements.Close();

    // Close and destroy all RSQLStatements
    TInt c( iStatements.Count() );
    for( TInt i=0; i<c; ++i )
        {
        iStatements[i]->Close();
        }
    iStatements.ResetAndDestroy();

    iTables.Close();
    CloseAllDatabases();

    delete iDbFile;
    iDatabaseHandles.Close();
    }

// ----------------------------------------------------------------------------
// Checks if all databases have been initialized.
// ----------------------------------------------------------------------------
//
EXPORT_C TBool CMPXDbManager::IsInitialized()
    {
    MPX_FUNC("CMPXDbManager::IsInitialized");
    return iInitialized;
    }

// ----------------------------------------------------------------------------
// Begins a transaction on all databases.
// ----------------------------------------------------------------------------
//
EXPORT_C void CMPXDbManager::BeginL()
    {
    MPX_FUNC("CMPXDbManager::BeginL");

    ASSERT(iTransactionCount >= 0);

    if (++iTransactionCount == 1)
        {
        DoBeginL();
        }
    }

void CMPXDbManager::DoBeginL()
    {
    MPX_FUNC("CMPXDbManager::DoBeginL");

    TInt err = iDatabase.Exec(KBeginTransaction);
        
    // transforms SQL error to KErrNotReady
    if( (err <= KSqlErrGeneral && err >= KSqlErrNotDb) || err == KSqlErrStmtExpired )
        {
        User::Leave(KErrNotReady);
        }
    else
        {
        User::LeaveIfError(err);
        }
    }

// ----------------------------------------------------------------------------
// Copy all DBs to RAM disk
// ----------------------------------------------------------------------------
//
EXPORT_C void CMPXDbManager::CopyDBsToRamL( TBool aIsMTPInUse )
    {
#ifdef __RAMDISK_PERF_ENABLE
    MPX_DEBUG1("-->CMPXDbManager::CopyDBsToRamL");
    if( iRAMDiskPerfEnabled )
        {
        if ( !IsRamDiskSpaceAvailable() )
            {
            return;
            }
        
        // Check if we are over the allowed ram space.
        TInt dbSize=0;
        TInt err = GetTotalDatabasesSize(dbSize);
        if ( err || (dbSize > iMaximumAllowedRAMDiskSpaceToCopy) )
            {
            MPX_DEBUG2("<--CMPXDbManager::CopyDBsToRamL Over the allowed Ram disk limit %Lu", iMaximumAllowedRAMDiskSpaceToCopy );
            return;
            }
        
        TInt transactionCount = iTransactionCount;
        if (iTransactionCount > 0) 
            {
            iTransactionCount = 0;
            DoCommitL();
            }

        TInt count(iDatabaseHandles.Count());
        for ( TInt i = 0; i < count ; ++i )
            {
            if ( ! iDatabaseHandles[i].iOpen )
                {
                MPX_DEBUG1("CMPXDbManager::CopyDBsToRamL DB not open (assuming drive is not present)");
                continue;
                }
            if ( iDatabaseHandles[i].iUseRAMdb )
                {
                // already used
                MPX_DEBUG1("CMPXDbManager::CopyDBsToRamL iUseRAMdb already ETrue");
                continue;
                }
            CloseDatabaseAtIndexL( i ); // let leave: not much we can do if we can't close the original DB
            DoCopyDBToRam( i, aIsMTPInUse ); // copies if it can
            TRAPD( err, OpenDatabaseAtIndexL( i ) );
            if ( err != KErrNone )
                {
                MPX_DEBUG2("CMPXDbManager::CopyDBsToRamL OpenDatabaseAtIndexL leave=%d", err);
                RemoveDummyFile(i);
                if ( iDatabaseHandles[i].iUseRAMdb ) 
                    {
                    // go back to disk DB
                    TRAP_IGNORE(CloseDatabaseAtIndexL( i ));
                    iDatabaseHandles[i].iUseRAMdb = EFalse;
                    OpenDatabaseAtIndexL( i );
                    continue;
                    }
                else
                    {
                    User::Leave( err );
                    }
                }
            }
            
        if (transactionCount > 0) 
            {
            DoBeginL();
            iTransactionCount = transactionCount;
            }
        }
    iRAMInUse = ETrue;
	
    MPX_DEBUG1("<--CMPXDbManager::CopyDBsToRamL");
#endif //__RAMDISK_PERF_ENABLE

    }


// ----------------------------------------------------------------------------
// CMPXDbManager::DoCopyDBToRam
// ----------------------------------------------------------------------------
//
TBool CMPXDbManager::DoCopyDBToRam( TInt aIndex, TBool aIsMTPInUse )
    {
#ifdef __RAMDISK_PERF_ENABLE
    MPX_DEBUG2("-->CMPXDbManager::DoCopyDBsToRam drive=%d", (TInt)iDatabaseHandles[aIndex].iDrive);
    DatabaseHandle& database = iDatabaseHandles[aIndex];
    TInt err = KErrNone;

    delete database.iOrigFullFilePath;
    database.iOrigFullFilePath = 0;
    delete database.iTargetFullFilePath;
    database.iTargetFullFilePath = 0;
    TRAP (err, 
	      database.iOrigFullFilePath = CreateFullFilenameL( database.iDrive );
          database.iUseRAMdb = ETrue; // must turn this on to create RAM filename
          database.iTargetFullFilePath = CreateFullFilenameL( database.iDrive );
          BaflUtils::EnsurePathExistsL( iFs, *database.iTargetFullFilePath ));
    database.iUseRAMdb = EFalse;
    if (err != KErrNone)
        {
        MPX_DEBUG1("CMPXDbManager::DoCopyDBsToRamL() CreateFilenameL or EnsurePathExistsL failed");
        return EFalse;
        }
    MPX_DEBUG2("RAMDisk src path=%S", database.iOrigFullFilePath);
    MPX_DEBUG2("RAMDisk dst path=%S", database.iTargetFullFilePath);

    if (!BlockDiskSpace( aIndex, aIsMTPInUse ) )
        {
        MPX_DEBUG1("CMPXDbManager::DoCopyDBsToRamL() BlockDiskSpace failed");
        return EFalse; // continue for next drive
        }

    if ( BaflUtils::CopyFile(iFs, *database.iOrigFullFilePath, *database.iTargetFullFilePath ) != KErrNone )
        {
        RemoveDummyFile( aIndex );
        return EFalse;
        }
    MPX_DEBUG2("RAMDisk Database copied=%d", (TInt)database.iDrive);
    database.iUseRAMdb = ETrue; // succeeded moving DB to RAM
    MPX_DEBUG1("<--CMPXDbManager::DoCopyDBsToRamL");
    return ETrue;
#else
    return EFalse;
#endif //__RAMDISK_PERF_ENABLE
    }

// ----------------------------------------------------------------------------
// Copy all DBs from RAM disk back to normal drives
// ----------------------------------------------------------------------------
//
EXPORT_C void CMPXDbManager::CopyDBsFromRamL()
    {
    MPX_FUNC("CMPXDbManager::CopyDBsFromRamL");
#ifdef __RAMDISK_PERF_ENABLE
    if( iRAMDiskPerfEnabled )
       {
        TInt transactionCount = iTransactionCount;
        if (iTransactionCount > 0) 
            {
            iTransactionCount = 0;
            TRAP_IGNORE( DoCommitL() );
            }

        TInt count(iDatabaseHandles.Count());
        TInt leaveError = KErrNone;
        iRAMInUse = EFalse;
        // Should not leave until all the databases have been copied from RAM drive. 
        for (TInt i = 0; i < count; ++i)
            {
            if ( !iDatabaseHandles[i].iUseRAMdb )
                {
                continue;
                }
            TRAPD( error, CloseDatabaseAtIndexL( i ) );
            if ( error )
                {
                // Can't close db on RAM drive, so cleanup.
                MPX_DEBUG2("CMPXDbManager::CopyDBsFromRamL CloseDatabaseAtIndexL fail: error = %d", error);
                // Delete database on RAM drive.
                BaflUtils::DeleteFile(iFs, *iDatabaseHandles[i].iTargetFullFilePath);
                // Delete dummy file
                RemoveDummyFile(i);
                }
            else
                {
                DoCopyDBFromRam(i);
                }
            iDatabaseHandles[i].iUseRAMdb = EFalse;
            // open db from drive
            TRAP( error, OpenDatabaseAtIndexL( i ) );      
            if ( error && !leaveError )
                {
                leaveError = error;
                }
            }
        
        // leave if error
        User::LeaveIfError(leaveError);

        if (transactionCount > 0) 
            {
            DoBeginL();
            iTransactionCount = transactionCount;
            }
        }
#endif //__RAMDISK_PERF_ENABLE
    }


// ----------------------------------------------------------------------------
// CMPXDbManager::DoCopyDBsToRam
// ----------------------------------------------------------------------------
//
void CMPXDbManager::DoCopyDBFromRam( TInt aIndex )
    {
#ifdef __RAMDISK_PERF_ENABLE
    MPX_DEBUG1("-->CMPXDbManager::DoCopyDBsFromRam");    
    DatabaseHandle& database = iDatabaseHandles[aIndex];

    //Copy Db from RAM to replace dummy file
    TRAPD(error, ReplaceFileL( *database.iTargetFullFilePath, database.iDummyFilePath));
    MPX_DEBUG2("CMPXDbManager::CopyDBsFromRam RAMDisk copied over dummy, error=%d", error);

    // done with RAM DB (whether copying succeeded or not) so can delete it
    // can ignore errors since we cannot do anything if this fails
    BaflUtils::DeleteFile(iFs, *database.iTargetFullFilePath);
    MPX_DEBUG1("CMPXDbManager::DoCopyDBsFromRam RAM DB deleted");
        
    if ( error == KErrNone )
        {
        // Delete old DB on drive
        // Can ignore error: either original does not exist or something is wrong and can't help it
        BaflUtils::DeleteFile(iFs, *database.iOrigFullFilePath);
        MPX_DEBUG1("CMPXDbManager::DoCopyDBsFromRam old DB on drive deleted");

        // Rename dummy file to be original file name
        error = BaflUtils::RenameFile(iFs, database.iDummyFilePath, *database.iOrigFullFilePath);
        MPX_DEBUG2("CMPXDbManager::CopyDBsFromRam dummy file renamed, error=%d", error);
        if ( error )
            {
            // Error renaming dummy file, delete dummy file.
            RemoveDummyFile(aIndex);
            }
        }
    else
        {
        RemoveDummyFile(aIndex);
        MPX_DEBUG1("CMPXDbManager::DoCopyDBsFromRam dummy file deleted");
        }

    MPX_DEBUG1("<--CMPXDbManager::DoCopyDBsFromRam");
#endif //__RAMDISK_PERF_ENABLE
    } 

// ----------------------------------------------------------------------------
// CMPXDbManager::ReplaceFileL
//
// Replaces a file with another writing over the destination file.
// Leaves on error.
// Implementation follows CFileMan::Copy except that 
//  - we don't resize target file to zero
//  - we can assume that source file already exists
//  - we don't copy file attributes & timestamp
// ----------------------------------------------------------------------------
//
void CMPXDbManager::ReplaceFileL( const TDesC& aSrcName, const TDesC& aDstName )
    {
    // open files
    RFile srcFile;
    User::LeaveIfError( srcFile.Open(iFs, aSrcName, EFileRead|EFileShareReadersOnly) );
    CleanupClosePushL( srcFile );
    
    RFile dstFile;
	TInt error = dstFile.Open(iFs, aDstName, EFileWrite|EFileWriteDirectIO|EFileShareExclusive);
	if (error == KErrNotFound)
	   {
	   error = dstFile.Create(iFs, aDstName, EFileWrite|EFileWriteDirectIO|EFileShareExclusive);
	   }
	User::LeaveIfError ( error );
    CleanupClosePushL( dstFile );
    
    // resize destination file
    TInt remainingBytes;
    User::LeaveIfError( srcFile.Size(remainingBytes) );
    User::LeaveIfError( dstFile.SetSize(remainingBytes) );

    // allocate buffer
   	const TInt KBigBufSize = 512 * 1024;
    const TInt KMediumBufSize = 32 * 1024;
    const TInt KSmallBufSize = 4 * 1024;
    HBufC8* bufPtr=HBufC8::New( Min(KBigBufSize, remainingBytes) );
    if (bufPtr==NULL)
        bufPtr=HBufC8::New(KMediumBufSize);
    if (bufPtr==NULL)
        bufPtr=HBufC8::New(KSmallBufSize);
    if (bufPtr == NULL)
        User::Leave(KErrNoMemory);
    CleanupStack::PushL(bufPtr);

    // copy
    TPtr8 copyBuf=bufPtr->Des();
    TInt pos=0;
    while( remainingBytes > 0 )
        {
        TInt s = Min( remainingBytes, copyBuf.MaxSize() );
        TInt ret = srcFile.Read(pos, copyBuf, s);
        if (ret == KErrNone && copyBuf.Length()!= s )
            {
            ret = KErrCorrupt;
            }
        if (ret == KErrNone)
            {
            ret = dstFile.Write(pos, copyBuf, s);
            }
        User::LeaveIfError (ret);
        pos += s;
        remainingBytes -= s;
        }
    User::LeaveIfError( dstFile.Flush() );
    CleanupStack::PopAndDestroy(3); // bufPtr, dstFile, srcFile
    }

// ----------------------------------------------------------------------------
// CMPXDbManager::RemoveDummyFile
// ----------------------------------------------------------------------------
//
void CMPXDbManager::RemoveDummyFile( TInt index )
    {
#ifdef __RAMDISK_PERF_ENABLE
    MPX_DEBUG1("-->CMPXDbManager::RemoveDummyFile");
       
    if ( iDatabaseHandles[index].iDummyFilePath.Length() )
        {
        BaflUtils::DeleteFile(iFs, iDatabaseHandles[index].iDummyFilePath);
        iDatabaseHandles[index].iDummyFilePath.Zero();
        }
    MPX_DEBUG1("<--CMPXDbManager::RemoveDummyFile");
#endif //__RAMDISK_PERF_ENABLE

    }


// ----------------------------------------------------------------------------
// Commits a transaction on all databases.
// ----------------------------------------------------------------------------
//
EXPORT_C void CMPXDbManager::CommitL()
    {
    MPX_FUNC("CMPXDbManager::CommitL");

    if(iTransactionCount > 0)
        {
        if (--iTransactionCount == 0)
            {
            DoCommitL();
            }
        }
    }
    
// ----------------------------------------------------------------------------
// Commits a transaction on all databases.
// ----------------------------------------------------------------------------
//
void CMPXDbManager::DoCommitL()
    {
    MPX_FUNC("CMPXDbManager::DoCommitL");
    TInt err = iDatabase.Exec(KCommitTransaction);
    
    // transforms SQL error to KErrNotReady
    if( (err <= KSqlErrGeneral && err >= KSqlErrNotDb) || err == KSqlErrStmtExpired )
        {
        MPX_DEBUG2("CMPXDbManager::CommitL failed err=%d", err);
        User::Leave(KErrNotReady);
        }
    else
        {
        User::LeaveIfError(err);
        }
    }

// ----------------------------------------------------------------------------
// Rolls back a transaction on all databases.
// ----------------------------------------------------------------------------
//
EXPORT_C void CMPXDbManager::RollbackL()
    {
    MPX_FUNC("CMPXDbManager::RollbackL");

    if(iTransactionCount > 0)
        {
        if (--iTransactionCount == 0)
            {
            TInt err = iDatabase.Exec(KRollbackTransaction);
            
            // transforms SQL error to KErrNotReady
            if( (err <= KSqlErrGeneral && err >= KSqlErrNotDb) || err == KSqlErrStmtExpired )
                {
                User::Leave(KErrNotReady);  
                }
            else
                {
                User::LeaveIfError(err);
                }
            }
    	}
    }

// ----------------------------------------------------------------------------
// Rolls back a transaction on all databases.
// ----------------------------------------------------------------------------
//
EXPORT_C TBool CMPXDbManager::InTransaction()
    {
    MPX_FUNC("CMPXDbManager::InTransaction");
    return iDatabase.InTransaction();
    }

// ----------------------------------------------------------------------------
// Tries to create and open the databases on all specified drives.
// ----------------------------------------------------------------------------
//
EXPORT_C void CMPXDbManager::InitDatabasesL(
    RArray<TInt> aDrives)
    {
    MPX_FUNC("CMPXDbManager::InitDatabasesL");

    CloseAllDatabases();

    TDriveUnit cdrive(KRootDrive());

    CreateDatabaseL(cdrive);
    OpenRootDatabaseL();

    TInt count(aDrives.Count());
    for (TInt i = 0; i < count; ++i)
        {
        TDriveUnit drive(aDrives[i]);
        if ((drive != cdrive) && !IsRemoteDrive(static_cast<TDriveNumber>(aDrives[i])))
            {
            const TDesC& driveName = drive.Name();

            DatabaseHandle handle;

            handle.iDrive = aDrives[i];
            handle.iAliasname = HBufC::NewL(KAliasName().Length());
            handle.iAliasname->Des().Format(KAliasName, &driveName);
            handle.iOpen = EFalse;
#ifdef __RAMDISK_PERF_ENABLE
            handle.iOrigFullFilePath = HBufC::NewL(0);
            handle.iTargetFullFilePath = HBufC::NewL(0);
            handle.iDummyFilePath.Zero();
            handle.iUseRAMdb = EFalse;
#endif //__RAMDISK_PERF_ENABLE

            TInt index = iDatabaseHandles.Count();
            iDatabaseHandles.AppendL(handle);

            TVolumeInfo vol;
            if (iFs.Volume(vol, drive) == KErrNone)
                {
                CreateDatabaseL(drive);
                AttachDatabaseL( index );
                }
            }
        }

    iInitialized = ETrue;
    }

// ----------------------------------------------------------------------------
// Opens a specified database.
// ----------------------------------------------------------------------------
//
EXPORT_C void CMPXDbManager::OpenDatabaseL(
    TInt aDrive)
    {
    MPX_FUNC("CMPXDbManager::OpenDatabaseL");

    if (iInitialized == EFalse)
        {
        User::Leave(KErrNotReady);
        }

    TDriveUnit drive(aDrive);
    TDriveUnit cdrive(KRootDrive());
    TBool found(EFalse);

    if ((drive != cdrive) && !IsRemoteDrive(static_cast<TDriveNumber>(aDrive)))
        {
        TInt count(iDatabaseHandles.Count());
        for (TInt i = 0; i < count; ++i)
            {
            if (iDatabaseHandles[i].iDrive == aDrive)
                {
                MPX_DEBUG2("CMPXDbManager::OpenDatabaseL found %d", aDrive);
                TInt transactionCount = iTransactionCount;
                if (iTransactionCount > 0) 
                    {
                    iTransactionCount = 0;
                    DoCommitL();
                    }
                OpenDatabaseAtIndexL( i );
                if (transactionCount > 0) 
                    {
                    DoBeginL();
                    iTransactionCount = transactionCount;
                    }
                found = ETrue;
                break;
                }
            }
        }
    if (!found)
        {
        MPX_DEBUG1("CMPXDbManager::OpenDatabaseL not found");
        User::Leave(KErrArgument);
        }

    // Close all prepared statements if a db is opened
    //
    ResetPreparedQueries();
    }
    
void CMPXDbManager::OpenDatabaseAtIndexL( TInt aIndex )
    {
    	  DatabaseHandle & database = iDatabaseHandles[aIndex];
        if (!database.iOpen)
            {
            MPX_DEBUG1("CMPXDbManager::OpenDatabaseAtIndexL not open");
            // make sure the database is created
            CreateDatabaseL( TDriveUnit(database.iDrive) );
            AttachDatabaseL( aIndex );
            }
    }

// ----------------------------------------------------------------------------
// Closes a specified database.
// ----------------------------------------------------------------------------
//
EXPORT_C void CMPXDbManager::CloseDatabaseL(
    TInt aDrive)
    {
    MPX_FUNC("CMPXDbManager::CloseDatabaseL");

    if (iInitialized == EFalse)
        {
        User::Leave(KErrNotReady);
        }
    
    TDriveUnit drive(aDrive);
    TDriveUnit cdrive(KRootDrive());
    TBool found(EFalse);

    if ((drive != cdrive) && !IsRemoteDrive(static_cast<TDriveNumber>(aDrive)))
        {
        TInt count(iDatabaseHandles.Count());
        for (TInt i = 0; i < count; ++i)
            {
            if (iDatabaseHandles[i].iDrive == aDrive)
                {
                TBool inTransaction = InTransaction();
                TInt transactionCount = iTransactionCount;
                iTransactionCount = 0;								
								
                if (inTransaction) //if the transaction is ongoing, try committing
                    {
                    //if transaction committing fails, try roll-back	
                    TInt error = iDatabase.Exec( KCommitTransaction );
                    if ( error != KErrNone )
                        {
                        //The error is ignored since we can't do nothing about it
                        iDatabase.Exec( KRollbackTransaction ); 
                        }
                    }
                	
#ifdef __RAMDISK_PERF_ENABLE                	
                if ( iRAMDiskPerfEnabled && iDatabaseHandles[i].iUseRAMdb )
            	      {
                    MPX_DEBUG2("CMPXDbManager::CloseDatabaseL found %d at RAM", aDrive);
                    TRAPD( err, CloseDatabaseAtIndexL( i ) );
                    if ( err != KErrNone )
                        {
                        // Can't close db on RAM drive, so cleanup.
                        MPX_DEBUG2("CMPXDbManager::CloseDatabaseL CloseDatabaseAtIndexL fail: error = %d", err);
                        // Delete dummy file
                        RemoveDummyFile(i);
                        iDatabaseHandles[i].iUseRAMdb = EFalse;
                        // Delete database on RAM drive.
                        User::LeaveIfError( BaflUtils::DeleteFile(iFs, *iDatabaseHandles[i].iTargetFullFilePath) );
                        }
                    else
                        {
                        DoCopyDBFromRam(i);
                        }
                    iDatabaseHandles[i].iUseRAMdb = EFalse;
                    }
                else
#endif
                    {
                    MPX_DEBUG2("CMPXDbManager::CloseDatabaseL found %d", aDrive);
                    CloseDatabaseAtIndexL( i );
                    }
                
                //Let MTP handle the transcation if there is any 
                if ( inTransaction ) 
                    {
                    DoBeginL();
                    iTransactionCount = transactionCount;
                    }

                found = ETrue;
                break;
                }
            }
        }
    if (!found)
        {
        MPX_DEBUG1("CMPXDbManager::CloseDatabaseL not found");
        User::Leave(KErrArgument);
        }

    }

void CMPXDbManager::CloseDatabaseAtIndexL( TInt aIndex )
    {
    // Close all prepared statements if a db is closed
    //
    ResetPreparedQueries();

    if (iDatabaseHandles[aIndex].iOpen)
        {
        MPX_DEBUG1("CMPXDbManager::CloseDatabaseAtIndexL found open");
        DetachDatabaseL( aIndex );
        }
}

// ----------------------------------------------------------------------------
// Closes all databases.
// ----------------------------------------------------------------------------
//
EXPORT_C void CMPXDbManager::CloseAllDatabases()
    {
    MPX_FUNC("CMPXDbManager::CloseAllDatabases");

    // Close all prepared statements if a db is closed
    //
    ResetPreparedQueries();

    TInt count(iDatabaseHandles.Count());
    for (TInt i = 0; i < count; ++i)
        {
        delete iDatabaseHandles[i].iAliasname;
        iDatabaseHandles[i].iAliasname = 0;
#ifdef __RAMDISK_PERF_ENABLE 
        RemoveDummyFile(i);            	
        delete iDatabaseHandles[i].iOrigFullFilePath;
        iDatabaseHandles[i].iOrigFullFilePath = 0;
        delete iDatabaseHandles[i].iTargetFullFilePath;
        iDatabaseHandles[i].iTargetFullFilePath = 0;
#endif //__RAMDISK_PERF_ENABLE 
        }

    iDatabaseHandles.Reset();
    iDatabase.Close();
    iInitialized = EFalse;
    }

// ----------------------------------------------------------------------------
// Open all databases.
// ----------------------------------------------------------------------------
//
EXPORT_C void CMPXDbManager::OpenAllDatabasesL()
    {
    MPX_FUNC("CMPXDbManager::OpenAllDatabasesL");

    if (!iInitialized)
        {
        OpenRootDatabaseL();
        }

    TInt count(iDatabaseHandles.Count());
    for (TInt i = 0; i < count; ++i)
        {
        TVolumeInfo vol;
        if (iFs.Volume(vol, iDatabaseHandles[i].iDrive) == KErrNone)
            {
            AttachDatabaseL( i );
            }
        }
    iInitialized = ETrue;

    // Close all prepared statements if a db is closed
    //
    ResetPreparedQueries();
    }

// ----------------------------------------------------------------------------
// Checks if the database on a specified drive is open.
// ----------------------------------------------------------------------------
//
EXPORT_C TBool CMPXDbManager::IsOpen(
    TInt aDrive) const
    {
    MPX_FUNC("CMPXDbManager::IsOpen");

    TDriveUnit drive(aDrive);
    TDriveUnit cdrive(KRootDrive());

    if (!iInitialized)
        {
        return EFalse;
        }
    else if (drive == cdrive)
        {
        return ETrue;
        }
    else
        {
        TInt count(iDatabaseHandles.Count());
        for (TInt i = 0; i < count; ++i)
            {
            if (iDatabaseHandles[i].iDrive == aDrive)
                {
                return iDatabaseHandles[i].iOpen;
                }
            }
        }

    return EFalse;
    }

// ----------------------------------------------------------------------------
// Returns the number of currently open databases.
// ----------------------------------------------------------------------------
//
EXPORT_C TInt CMPXDbManager::DatabaseCount() const
    {
    MPX_FUNC("CMPXDbManager::DatabaseCount");

    TInt openCount(0);
    if (iInitialized)
        {
        ++openCount;

        TInt count(iDatabaseHandles.Count());
        for (TInt i = 0; i < count; ++i)
            {
            if (iDatabaseHandles[i].iOpen)
                {
                ++openCount;
                }
            }
        }

    return openCount;
    }

// ----------------------------------------------------------------------------
// Returns the drive corresponding to a given index.
// ----------------------------------------------------------------------------
//
EXPORT_C TInt CMPXDbManager::DbDrive(
    TInt aIndex) const
    {
    MPX_FUNC("CMPXDbManager::DbDrive");

    ASSERT((aIndex >= 0) || (aIndex < iDatabaseHandles.Count()));
    return iDatabaseHandles[aIndex].iDrive;
    }

// ----------------------------------------------------------------------------
// Recreate a specified database.
// ----------------------------------------------------------------------------
//
EXPORT_C void CMPXDbManager::RecreateDatabaseL(
    TInt aDrive)
    {
    MPX_FUNC("CMPXDbManager::RecreateDatabaseL");

    if (iInitialized == EFalse)
        {
        User::Leave(KErrNotReady);
        }

    TInt index = KErrNotFound;

    if (aDrive == EDriveC)
        {
        index = iDatabaseHandles.Count();
        }
    else
        {
        TInt count(iDatabaseHandles.Count());
        for (TInt i = 0; i < count; ++i)
            {
            if ((iDatabaseHandles[i].iDrive == aDrive) && (iDatabaseHandles[i].iOpen))
                {
                index = i;
                break;
                }
            }
        }
    if ( index >= 0 )
        {
        HBufC * filename = CreateFilenameL(aDrive);
        CleanupStack::PushL(filename);

        TRAPD(err, DoRecreateDatabaseL(filename));
        if(err < 0)
            {
            TDriveUnit drive_unit(aDrive);

            if(aDrive == EDriveC)
                {
                iDatabase.Close();
                iInitialized = EFalse;

                RSqlDatabase::Delete(*filename);
                CreateDatabaseL(drive_unit);

                User::LeaveIfError(iDatabase.Open(*filename));
                iInitialized = ETrue;
                }
            else
                {
                DetachDatabaseL( index );

                RSqlDatabase::Delete(*filename);
                CreateDatabaseL(drive_unit);

                AttachDatabaseL( index );
                }
            }

        CleanupStack::PopAndDestroy(filename);
        }
    else
        {
        User::Leave(KErrNotFound);
        }
    }

// ----------------------------------------------------------------------------
// Recreate all databases.
// ----------------------------------------------------------------------------
//
EXPORT_C void CMPXDbManager::RecreateAllDatabasesL()
    {
    MPX_FUNC("CMPXDbManager::RecreateAllDatabasesL");

    if (iInitialized == EFalse)
        {
        User::Leave(KErrNotReady);
        }

    // Recreate on drive C
    RecreateDatabaseL(EDriveC);

    // Recreate all attached drives
    TInt count(iDatabaseHandles.Count());
    for (TInt i = 0; i < count; ++i)
        {
        if (iDatabaseHandles[i].iOpen)
            {
            RecreateDatabaseL(iDatabaseHandles[i].iDrive);
            }
        }
    }

// ----------------------------------------------------------------------------
// Returns current DB version
// ----------------------------------------------------------------------------
//
EXPORT_C TVersion CMPXDbManager::Version() const
    {
    MPX_FUNC("CMPXDbManager::Version");
    return TVersion(KMPXDbVersion[0], KMPXDbVersion[1], KMPXDbVersion[2]);
    }

// ----------------------------------------------------------------------------
// Registes a table with the database
// ----------------------------------------------------------------------------
//
EXPORT_C void CMPXDbManager::RegisterTableL(
    MMPXTable& aTable)
    {
    MPX_FUNC("CMPXDbManager::RegisterTableL");
    iTables.AppendL(&aTable);
    }

// ----------------------------------------------------------------------------
// Executes a select query with variable number of parameters
// The query is executed on all available databases with a format like:
//
//      <query on database1> UNION ALL <query on database2> ...
//
// The query string passed in by the caller must have the ":dbname" prefix for all
// the tables in the FROM clause. This will be replaced with the right alias for
// attached databases or with no alias for the C database.
//
// In case the original query contains an ORDER BY clause, this will be extracted
// and added at the end of the union query.
//
// Note: Running the union query seems to be similar in speed even if one of the
// databases is empty and therefore no optimization was done for this case.
// ----------------------------------------------------------------------------
//
EXPORT_C RSqlStatement CMPXDbManager::ExecuteSelectQueryL(
    TRefByValue<const TDesC> aFmt,
    ...)
    {
    MPX_FUNC("CMPXDatabase::ExecuteSelectQueryL");

    VA_LIST list;
    VA_START(list, aFmt);

    // Will reallocate
    HBufC* selectBuf = FormatQueryLC(aFmt, list);
    RSqlStatement statement = ExecuteSelectQueryOnAllDrivesL(selectBuf->Des());
    CleanupStack::PopAndDestroy(selectBuf);

    VA_END(list);

    return statement;
    }

// ----------------------------------------------------------------------------
// Executes a select query against a specified drive
// ----------------------------------------------------------------------------
//
EXPORT_C RSqlStatement CMPXDbManager::ExecuteSelectQueryL(
    TInt aDrive,
    TRefByValue<const TDesC> aFmt,
    ...)
    {
    MPX_FUNC("CMPXDatabase::ExecuteSelectQueryL");

    VA_LIST list;
    VA_START(list, aFmt);

    // Will reallocate
    HBufC* selectBuf = FormatQueryLC(aFmt, list);
    RSqlStatement statement = ExecuteSelectQueryOnDriveL(aDrive, selectBuf->Des());
    CleanupStack::PopAndDestroy(selectBuf);

    VA_END(list);

    return statement;
    }

// ----------------------------------------------------------------------------
// CMPXDbManager::ExecuteSelectQueryL
// ----------------------------------------------------------------------------
//
EXPORT_C RSqlStatement& CMPXDbManager::ExecuteSelectQueryL(
    TUint aStatementId,
    TInt aFirstValue,
    TInt aSecondValue,
    TRefByValue<const TDesC> aFmt,
    ...)
    {
    MPX_FUNC("CMPXDatabase::ExecuteOffsetSelectQueryL");

    // Prepare the Query first
    VA_LIST list;
    VA_START(list, aFmt);
    RSqlStatement& statement = PrepareQueryL( aStatementId, aFmt, list );
    VA_END(list);

    // Bind the Limit and Offset variables
    User::LeaveIfError(statement.BindInt(0, aFirstValue));
    User::LeaveIfError(statement.BindInt(1, aSecondValue));

    return statement;
    }

// ----------------------------------------------------------------------------
// CMPXDbManager::ExecuteSelectQueryL
// ----------------------------------------------------------------------------
//
EXPORT_C RSqlStatement& CMPXDbManager::ExecuteSelectQueryL( TUint aStatementId,
                                                            const TDesC& aFirstValue,
                                                            TInt aSecondValue,
                                                            TRefByValue<const TDesC> aFmt, ...)
    {
    MPX_FUNC("CMPXDbManager::ExecuteMediaAscQueryL");

    // Prepare the Query first
    VA_LIST list;
    VA_START(list, aFmt);
    RSqlStatement& statement = PrepareQueryL( aStatementId, aFmt, list );
    VA_END(list);

    // bind the title and limit values
    User::LeaveIfError(statement.BindText(0, aFirstValue));
    User::LeaveIfError(statement.BindInt(1, aSecondValue));

    return statement;
    }

// ----------------------------------------------------------------------------
// Executes a query that does not return a record set (INSERT, UPDATE, DELETE,
// CREATE, DROP, etc).
//
// If a valid drive is specified then the query is only executed only on
// that drive. If KDbManagerAllDrives is specified then the query is executed
// separately on each available drive.
// ----------------------------------------------------------------------------
//
EXPORT_C void CMPXDbManager::ExecuteQueryL(
    TInt aDrive,
    TRefByValue<const TDesC> aFmt,
    ...)
    {
    MPX_FUNC("CMPXDatabase::ExecuteQueryL");

    // make sure there is enough space on all drives affected
    CheckDiskSpaceL(aDrive);

    VA_LIST list;
    VA_START(list, aFmt);

    HBufC* selectBuf = FormatQueryLC(aFmt, list);
    TPtr selectBufPtr = selectBuf->Des();
    TInt dbCount(iDatabaseHandles.Count());

    // a specified drive or all drives
    TInt loopCount = (aDrive == KDbManagerAllDrives) ? (dbCount + 1) : 1;
    TBool queryExecuted(EFalse); // flag to check if the query was executed at least once
    for (TInt j = 0; j < loopCount; ++j)
        {
        HBufC* query = HBufC::NewLC(selectBufPtr.Length() + KBufIncrement);
        TPtr queryPtr = query->Des();
        queryPtr.Copy(selectBufPtr);
        if (aDrive == EDriveC) // if C drive only
            {
            RemoveDriveAlias(queryPtr);
            }
        else // all drives or a particular drive other than C drive
            {
            if (aDrive == 0) // all drives
                {
                if (j == dbCount) // C drive
                    {
                    RemoveDriveAlias(queryPtr);
                    }
                else //all other drives, except C drive
                    {
                    if (iDatabaseHandles[j].iOpen)
                        {
                        ReplaceDriveAlias(queryPtr, *(iDatabaseHandles[j].iAliasname));
                        }
                    }
                }
            else //a particular drive, other than C drive
                {
                for (TInt i = 0; i < dbCount; ++i)
                    {
                    if (iDatabaseHandles[i].iOpen && iDatabaseHandles[i].iDrive == aDrive)
                        {
                        ReplaceDriveAlias(queryPtr, *(iDatabaseHandles[i].iAliasname));
                        break;
                        }
                    }
                }
            }
        TInt dbnamePos = queryPtr.Find(KDBNameToken);// check if the query was created correctly
        if (dbnamePos == KErrNotFound)
            {
            // log the query
            TPtrC ptr(query->Left(KMaxLogQuery));
            MPX_DEBUG2("Query: %S", &ptr);

            User::LeaveIfError(ExecuteSqlStatement(iDatabase, queryPtr));
            queryExecuted = ETrue;
            }
        CleanupStack::PopAndDestroy(query);
        }   //for (TInt j = 0; j < loopCount; ++j)
    CleanupStack::PopAndDestroy(selectBuf);
    VA_END(list);
    if (!queryExecuted && aDrive !=   0)
        {
        // the requested drive(s) is not open
        User::Leave(KErrNotFound);
        }
    }

// ----------------------------------------------------------------------------
// CMPXDbManager::FormatQueryLC
// ----------------------------------------------------------------------------
//
HBufC* CMPXDbManager::FormatQueryLC(
    TRefByValue<const TDesC> aFmt,
    VA_LIST aList)
    {
    MPX_FUNC("CMPXDatabase::FormatQueryLC");

    TOverflowHandle overflow;

    HBufC* selectBuf = HBufC::NewLC(TDesC(aFmt).Length());//will reallocate
    selectBuf->Des().AppendFormatList(aFmt, aList, &overflow);
    while (overflow.GetOverflowFlag())
        {
        TInt len = selectBuf->Des().MaxLength() + KBufIncrement;
        CleanupStack::PopAndDestroy(selectBuf);
        selectBuf = HBufC::NewLC(len);
        selectBuf->Des().AppendFormatList(aFmt, aList, &overflow);
        }

    return selectBuf;
    }

// ----------------------------------------------------------------------------
// Executes a select query against a specified drive
// ----------------------------------------------------------------------------
//
EXPORT_C RSqlStatement CMPXDbManager::ExecuteSelectQueryOnAllDrivesL(
    TInt aDrive,
    TRefByValue<const TDesC> aFmt,
    ...)
    {
    MPX_FUNC("CMPXDatabase::ExecuteSelectQueryL");

    VA_LIST list;
    VA_START(list, aFmt);

    // Will reallocate
    HBufC* selectBuf = FormatQueryLC(aFmt, list);
    RSqlStatement statement = ExecuteSelectQueryOnAllDrivesL(aDrive, selectBuf->Des());
    CleanupStack::PopAndDestroy(selectBuf);

    VA_END(list);

    return statement;
    }

// ----------------------------------------------------------------------------
// CMPXDbManager::ExecuteSelectQueryOnAllDrivesL
// ----------------------------------------------------------------------------
//
RSqlStatement CMPXDbManager::ExecuteSelectQueryOnAllDrivesL(
    TPtr aQuery)
    {
    MPX_FUNC("CMPXDatabase::ExecuteSelectQueryOnAllDrivesL");

    TInt dbCount = iDatabaseHandles.Count();
    HBufC* query = HBufC::NewLC(aQuery.Length() * (dbCount + 1) +
        KUnionAllToken().Length() * dbCount);
    TPtr queryPtr = query->Des();
    HBufC* selectOutBuf = NULL;
    TInt enclosed = aQuery.Mid(1, aQuery.Length() - 1).Find(KSelectToken);
    if (enclosed != KErrNotFound)
        {
        enclosed++;//to compensate the indent
        selectOutBuf = HBufC::NewLC(aQuery.Length() * (dbCount + 1) +
            KUnionAllToken().Length() * dbCount);
        selectOutBuf->Des().Copy(aQuery.Left(enclosed));
        selectOutBuf->Des().Append(aQuery.Right(1));//the closing bracket
        aQuery.Delete(0, enclosed);
        aQuery.Delete(aQuery.Length() - 1, 1);
        }

    HBufC* orderBuf = NULL;
    TInt orderPos = aQuery.Find(KOrderByToken);
    if (orderPos != KErrNotFound)
        {
        orderBuf = aQuery.Right(aQuery.Length() - orderPos).AllocL();
        aQuery.Delete(orderPos, aQuery.Length() - orderPos);
        }
    queryPtr.Append(aQuery);// for cdrive
    RemoveDriveAlias(queryPtr);
    for (TInt i = 0; i < dbCount; ++i)//for other drives
        {
        if (iDatabaseHandles[i].iOpen)
            {
            queryPtr.Append(KUnionAllToken);
            queryPtr.Append(aQuery);
            ReplaceDriveAlias(queryPtr, *(iDatabaseHandles[i].iAliasname));
            }
        }
    if (orderBuf)
        {
        queryPtr.Append(orderBuf->Des());
        }
    delete orderBuf;
    if (enclosed != KErrNotFound)
        {
        selectOutBuf->Des().Insert(enclosed, query->Des());
        queryPtr.Copy(selectOutBuf->Des());
        CleanupStack::PopAndDestroy(selectOutBuf);
        }

    // Log the query string before execution
    TPtrC ptr(query->Left(KMaxLogQuery));
    MPX_DEBUG2("Query: %S", &ptr);

    // Return a temporary statement and not a member variable.
    // This ensures that a copy is done and a second embedded query can be
    // executed while the first result set is processed.
    RSqlStatement statement;
    User::LeaveIfError(statement.Prepare(iDatabase, queryPtr));
    CleanupStack::PopAndDestroy(query);

    return statement;
    }

// ----------------------------------------------------------------------------
// CMPXDbManager::ExecuteSelectQueryOnAllDrivesL
// ----------------------------------------------------------------------------
//
RSqlStatement CMPXDbManager::ExecuteSelectQueryOnAllDrivesL( TInt aDrive,
    TPtr aQuery)
    {
    MPX_FUNC("CMPXDatabase::ExecuteSelectQueryOnAllDrivesL");

    TInt dbCount = iDatabaseHandles.Count();
    HBufC* query = HBufC::NewLC(aQuery.Length() * (dbCount + 1) +
        KUnionAllToken().Length() * dbCount);
    TPtr queryPtr = query->Des();
    HBufC* selectOutBuf = NULL;
    TInt enclosed = aQuery.Mid(1, aQuery.Length() - 1).Find(KSelectToken);
    if (enclosed != KErrNotFound)
        {
        enclosed++;//to compensate the indent
        selectOutBuf = HBufC::NewLC(aQuery.Length() * (dbCount + 1) +
            KUnionAllToken().Length() * dbCount);
        selectOutBuf->Des().Copy(aQuery.Left(enclosed));
        selectOutBuf->Des().Append(aQuery.Right(1));//the closing bracket
        aQuery.Delete(0, enclosed);
        aQuery.Delete(aQuery.Length() - 1, 1);
        }

    HBufC* orderBuf = NULL;
    TInt orderPos = aQuery.Find(KOrderByToken);
    if (orderPos != KErrNotFound)
        {
        orderBuf = aQuery.Right(aQuery.Length() - orderPos).AllocL();
        aQuery.Delete(orderPos, aQuery.Length() - orderPos);
        }
    
    //remove KPlDBNameToken
    if ( aDrive == EDriveC )//if playlist on c drive
    	{
    	RemoveDriveAlias(aQuery,KPlDBNameToken);
    	}
    else
    	{//for other drives
	    for (TInt i = 0; i < dbCount; ++i)
	        {
	        if (iDatabaseHandles[i].iOpen && (iDatabaseHandles[i].iDrive == aDrive))
	            {
	            ReplaceDriveAlias(aQuery, *(iDatabaseHandles[i].iAliasname),
	            		KPlDBNameToken);
	            break;
	            }
	        }
    	}
    
    queryPtr.Append(aQuery);// for cdrive
    RemoveDriveAlias(queryPtr);
    for (TInt i = 0; i < dbCount; ++i)//for other drives
        {
        if (iDatabaseHandles[i].iOpen)
            {
            queryPtr.Append(KUnionAllToken);
            queryPtr.Append(aQuery);
            ReplaceDriveAlias(queryPtr, *(iDatabaseHandles[i].iAliasname));
            }
        }
   
    if (orderBuf)
        {
        queryPtr.Append(orderBuf->Des());
        }
    delete orderBuf;
    if (enclosed != KErrNotFound)
        {
        selectOutBuf->Des().Insert(enclosed, query->Des());
        queryPtr.Copy(selectOutBuf->Des());
        CleanupStack::PopAndDestroy(selectOutBuf);
        }

    // Log the query string before execution
    TPtrC ptr(query->Left(KMaxLogQuery));
    MPX_DEBUG2("Query: %S", &ptr);

    // Return a temporary statement and not a member variable.
    // This ensures that a copy is done and a second embedded query can be
    // executed while the first result set is processed.
    RSqlStatement statement;
    TInt err(statement.Prepare(iDatabase, queryPtr));
    User::LeaveIfError(err);
    CleanupStack::PopAndDestroy(query);

    return statement;
    }

// ----------------------------------------------------------------------------
// CMPXDbManager::ExecuteSelectQueryOnDriveLryLC
// ----------------------------------------------------------------------------
//
RSqlStatement CMPXDbManager::ExecuteSelectQueryOnDriveL(
    TInt aDrive,
    TPtr aQuery)
    {
    MPX_FUNC("CMPXDatabase::ExecuteSelectQueryOnDriveL");

    RSqlStatement statement;
    if (KDbManagerAllDrives == aDrive)
        {
        statement = ExecuteSelectQueryOnAllDrivesL(aQuery);
        }
    else
        {
        TInt dbCount(iDatabaseHandles.Count());

        // flag to check if the query was executed at least once
        TBool queryExecuted = EFalse;

        HBufC* query = HBufC::NewLC(aQuery.Length() + KBufIncrement);
        TPtr queryPtr = query->Des();
        queryPtr.Copy(aQuery);
        if (aDrive == EDriveC) //if C drive
            {
            RemoveDriveAlias(queryPtr);
            }
        else // drive other than C drive
            {
            for (TInt i = 0; i < dbCount; ++i)
                {
                if (iDatabaseHandles[i].iOpen && (iDatabaseHandles[i].iDrive == aDrive))
                    {
                    ReplaceDriveAlias(queryPtr, *(iDatabaseHandles[i].iAliasname));
                    break;
                    }
                }
            }

        TInt dbnamePos = queryPtr.Find(KDBNameToken);// check if the query was created correctly
        if (dbnamePos == KErrNotFound)
            {
            // Log the query string before execution
            TPtrC ptr(query->Left(KMaxLogQuery));
            MPX_DEBUG2("Query: %S", &ptr);

            User::LeaveIfError(statement.Prepare(iDatabase, queryPtr));
            queryExecuted = ETrue;
            }
        CleanupStack::PopAndDestroy(query);

        if (!queryExecuted)
            {
            // the requested drive(s) is not open
            User::Leave(KErrNotFound);
            }
        }

    return statement;
    }

// ----------------------------------------------------------------------------
// Prepare a query for execution on all open database. This query's lifetime
// is owned by the dbmanager
// ----------------------------------------------------------------------------
//
RSqlStatement& CMPXDbManager::PrepareQueryL( TUint aStatementId,
                                             TRefByValue<const TDesC> aFmt,
                                             VA_LIST aList )
    {
    // Try to find the query first if it has been created
    TInt index(KErrNotFound);
    TInt c(iPreparedStatements.Count());

    for( TInt i=0; i<c; ++i )
        {
        if( iPreparedStatements[i].iId == aStatementId )
            {
            index = i;
            break;
            }
        }

    // If the index isn't found we create a new query statement
    //
    if( index == KErrNotFound )
        {
        RSqlStatement* newStatement = new(ELeave) RSqlStatement();
        CleanupStack::PushL(newStatement);

        TSqlStatementState newState;
        newState.iId = aStatementId;
        newState.iPrepared = EFalse;
        iPreparedStatements.AppendL( newState );

        TInt err = iStatements.Append( newStatement ); // ownership x-fer
        if (err != KErrNone)
            {
            iPreparedStatements.Remove(c);
            User::Leave(err);
            }
        CleanupStack::Pop(newStatement);
        index = c;
        }

    // Finally create the statement
    if ( !iPreparedStatements[index].iPrepared )
        {

        // Will reallocate
        HBufC* selectBuf = FormatQueryLC(aFmt, aList);
        TPtr selectBufPtr = selectBuf->Des();
        TInt dbCount = iDatabaseHandles.Count();
        HBufC* query = HBufC::NewLC(selectBufPtr.Length() * (dbCount + 1) +
            KUnionAllToken().Length() * dbCount);
        TPtr queryPtr = query->Des();
        HBufC* selectOutBuf = NULL;
        TInt enclosed = selectBufPtr.Mid(1,selectBufPtr.Length() - 1).Find(KSelectToken);
        if (enclosed != KErrNotFound)
            {
            enclosed++;//to compensate the indent
            selectOutBuf = HBufC::NewLC(selectBufPtr.Length() * (dbCount + 1) +
                KUnionAllToken().Length() * dbCount);
            selectOutBuf->Des().Copy(selectBufPtr.Left(enclosed));
            selectOutBuf->Des().Append(selectBufPtr.Right(1));//the closing bracket
            selectBufPtr.Delete(0, enclosed);
            selectBufPtr.Delete(selectBufPtr.Length()   -   1, 1);
            }

        HBufC* orderBuf = NULL;
        TInt orderPos = selectBufPtr.Find(KOrderByToken);
        if (orderPos != KErrNotFound)
            {
            orderBuf = selectBufPtr.Right(selectBufPtr.Length() - orderPos).AllocL();
            selectBufPtr.Delete(orderPos,   selectBufPtr.Length() - orderPos);
            }
        queryPtr.Append(selectBufPtr);// for cdrive
        RemoveDriveAlias(queryPtr);
        for (TInt i = 0; i < dbCount; ++i)//for other drives
            {
            if (iDatabaseHandles[i].iOpen)
                {
                queryPtr.Append(KUnionAllToken);
                queryPtr.Append(selectBufPtr);
                ReplaceDriveAlias(queryPtr, *(iDatabaseHandles[i].iAliasname));
                }
            }
        if (orderBuf)
            {
            queryPtr.Append(orderBuf->Des());
            }
        delete orderBuf;
        if (enclosed != KErrNotFound)
            {
            selectOutBuf->Des().Insert(enclosed, query->Des());
            queryPtr.Copy(selectOutBuf->Des());
            CleanupStack::PopAndDestroy(selectOutBuf);
            }

        // Log the query string before execution
        TPtrC ptr(query->Left(KMaxLogQuery));
        MPX_DEBUG2("Query: %S", &ptr);

        // use the member variable statement
        User::LeaveIfError(iStatements[index]->Prepare(iDatabase, queryPtr));
        CleanupStack::PopAndDestroy(2, selectBuf); //query

        iPreparedStatements[index].iPrepared = ETrue;
        }
    else
        {
        iStatements[index]->Reset();
        }

    return *iStatements[index];
    }

// ----------------------------------------------------------------------------
// Resets all prepared queries
// ----------------------------------------------------------------------------
//
void CMPXDbManager::ResetPreparedQueries()
    {
    MPX_FUNC("CMPXDbManager::ResetPreparedQueries");
    iPreparedStatements.Reset();

    TInt c( iStatements.Count() );
    for( TInt i=0; i<c; ++i )
        {
        iStatements[i]->Close();
        }
    iStatements.ResetAndDestroy();
    }

// ----------------------------------------------------------------------------
// Asks all registered tables to create themselves
// ----------------------------------------------------------------------------
//
EXPORT_C void CMPXDbManager::CreateTablesL(
    RSqlDatabase& aDatabase)
    {
    MPX_FUNC("CMPXDbManager::CreateTablesL");

	CreateTablesL(aDatabase, EFalse);
    }

// ----------------------------------------------------------------------------
// CleanupTransaction: close transaction when creating DB
// ----------------------------------------------------------------------------
//
static void CleanupTransaction(TAny * aDatabase)
    {
    TInt err = ((RSqlDatabase*)aDatabase)->Exec(KRollbackTransaction);
    MPX_DEBUG2("CMPXDbManager CleanupTransaction rollback, error %d", err);
    }
    
// ----------------------------------------------------------------------------
// CMPXDbManager::CreateTablesL
// ----------------------------------------------------------------------------
//
void CMPXDbManager::CreateTablesL(
	RSqlDatabase& aDatabase,
	TBool aCorrupt)
	{
	MPX_FUNC("CMPXDbManager::CreateTablesL");
    TInt err = aDatabase.Exec(KBeginTransaction);
    if (err < 0)
       {
       MPX_DEBUG2("SQL BEGIN TRANSACTION error %d", err);
       User::Leave (err);
       }
    CleanupStack::PushL(TCleanupItem(&CleanupTransaction, &aDatabase));
    TInt count(iTables.Count());
    for (TInt i = 0; i < count; ++i)
        {
        iTables[i]->CreateTableL(aDatabase, aCorrupt);
        }
    err = aDatabase.Exec(KCommitTransaction);
    if (err < 0)
        {
        MPX_DEBUG2("SQL COMMIT TRANSACTION error %d", err);
        User::Leave (err);
        }
    CleanupStack::Pop();
	}

// ----------------------------------------------------------------------------
// Opens root database on C-drive
// ----------------------------------------------------------------------------
//
void CMPXDbManager::OpenRootDatabaseL()
    {
    MPX_FUNC("CMPXDbManager::OpenRootDatabaseL");
        TDriveUnit cdrive(KRootDrive());
    HBufC * filename = CreateFilenameL(cdrive);
    CleanupStack::PushL(filename);
    User::LeaveIfError(iDatabase.Open(*filename));

    CleanupStack::PopAndDestroy(filename);
    }

// ----------------------------------------------------------------------------
// Creates a specified database.
// ----------------------------------------------------------------------------
//
void CMPXDbManager::CreateDatabaseL(
    TDriveUnit aDrive)
    {
    MPX_FUNC("CMPXDbManager::CreateDatabaseL");

    RSqlDatabase database;
    CleanupClosePushL(database);

    HBufC* filename = CreateFilenameL(aDrive);
    CleanupStack::PushL(filename);

    if (database.Open(filename->Des()) != KErrNone)
        {
        MPX_DEBUG3("CMPXDbManager::CreateDatabaseL - cannot open db on drive %d %S", TInt(aDrive), filename);

        // close the database first
        database.Close();
        DoCreateDatabaseL( aDrive );
        }
    else
        {
        TBool tableOK(ETrue);

        // try to detect any corrupt tables
        TInt count(iTables.Count());
        for (TInt i = 0; i < count; ++i)
            {
            // ask the table to check its structure
            if (!iTables[i]->CheckTableL(database))
                {
                tableOK = EFalse;
                break;
                }
            }

        if (!tableOK)
            {
            // close the database first
            database.Close();
			
			// delete database and create database
            DoCreateDatabaseL( aDrive );
            }
        }
    CleanupStack::PopAndDestroy(filename);
    CleanupStack::PopAndDestroy(&database);
    }

// ----------------------------------------------------------------------------
// Attaches a specified database.
// ----------------------------------------------------------------------------
//
void CMPXDbManager::AttachDatabaseL( TInt aIndex )
    {
    MPX_FUNC("CMPXDbManager::AttachDatabaseL");
    ASSERT( aIndex < iDatabaseHandles.Count() );
    DatabaseHandle & database = iDatabaseHandles[ aIndex ];
    if (!database.iOpen)
        {
        HBufC* filename = CreateFilenameL( database.iDrive );
        CleanupStack::PushL(filename);
                
#ifdef __RAMDISK_PERF_ENABLE
        if( database.iUseRAMdb )
            {
            delete database.iAliasname;
            database.iAliasname = HBufC::NewL(KAliasName().Length());
            HBufC* temp = HBufC::NewLC(2); // form of DE, DF, DX,...
            temp->Des().Append(iRAMDrive); // length == 2
            TDriveUnit pdrive( database.iDrive );
            temp->Des().Append(pdrive.Name().Left(1)); //length == 2+ 1
            database.iAliasname->Des().Format(KRAMAliasName, temp);
            MPX_DEBUG2("CMPXDbManager::AttachDatabaseL - RAM change aliasname of %S", database.iAliasname );
            CleanupStack::PopAndDestroy(temp);
            }
        else
#endif //__RAMDISK_PERF_ENABLE
            {
            delete database.iAliasname;
            TDriveUnit drive( database.iDrive );
            const TDesC& driveName = drive.Name();
            database.iAliasname = HBufC::NewL(KAliasName().Length());
            database.iAliasname->Des().Format(KAliasName, &driveName);
            MPX_DEBUG2("CMPXDbManager::AttachDatabaseL - normal change aliasname of %S", database.iAliasname);
            }

        TInt err = iDatabase.Attach( *filename, *database.iAliasname );
        MPX_DEBUG2("CMPXDbManager::AttachDatabaseL - Attach Error =%d", err);
        User::LeaveIfError(err);
        database.iOpen = ETrue;

        CleanupStack::PopAndDestroy(filename);
        }
    else
        {
        MPX_DEBUG1("CMPXDbManager::AttachDatabaseL - found already open");    
        }
    }

// ----------------------------------------------------------------------------
// Detaches a specified database.
// ----------------------------------------------------------------------------
//
void CMPXDbManager::DetachDatabaseL( TInt aIndex )
    {
    MPX_FUNC("CMPXDbManager::DetachDatabaseL");

    ASSERT( iInitialized && aIndex < iDatabaseHandles.Count() );
    DatabaseHandle & database = iDatabaseHandles[ aIndex ];
    if ( database.iOpen )
        {
        MPX_DEBUG2("CMPXDbManager::DetachDatabaseL iAliasname=%S is open",database.iAliasname );
        TInt err = iDatabase.Detach(*(database.iAliasname));
        if ( err )
            {
            MPX_DEBUG2("CMPXDbManager::DetachDatabaseL detach failed Error=%d", err);
            }
        User::LeaveIfError(err);
        database.iOpen = EFalse;
        }
    }

// ----------------------------------------------------------------------------
// Creates the absolute database filename on a specified drive.
// ----------------------------------------------------------------------------
//
HBufC* CMPXDbManager::CreateFilenameL(
    TDriveUnit aDrive)
    {
    MPX_FUNC("CMPXDbManager::CreateFilenameL");

    HBufC* filename = HBufC::NewL(KMaxFileName);

    const TDesC& securefilePath = KSecureFilePath;
    TDriveUnit cdrive(KRootDrive());

#ifdef __RAMDISK_PERF_ENABLE
    TInt index(GetDatabaseIndex((TInt)aDrive));    
    if ( index >=0 && iDatabaseHandles[index].iUseRAMdb && aDrive != cdrive )
        {
        MPX_DEBUG1("CMPXDbManager::CreateFilenameL - use RAMDisk");
        TFileName path;
        path.Append(iRAMDrive);
        path.Append(_L(":"));
        TBuf<2> d;
        d.Append(aDrive.Name());
        TFileName temp;
        temp.Append(d.Left(1)); // attach original drive name
        temp.Append(iDbFile->Des()); 
        filename->Des().Format(securefilePath, &path, User::Identity().iUid, &temp);
        MPX_DEBUG3("CMPXDbManager::CreateFilenameL - path=%S filename=%S", &path, filename);
        }
    else
#endif //__RAMDISK_PERF_ENABLE
        {
        MPX_DEBUG1("CMPXDbManager::CreateFilenameL - use normal drive");
        const TDesC& driveName = aDrive.Name();
        filename->Des().Format(securefilePath, &driveName, User::Identity().iUid, iDbFile);
        }
    
    MPX_DEBUG2("CMPXDbManager::CreateFilenameL filename = %S", filename); 
    return filename;
    }

// ----------------------------------------------------------------------------
// Replaces :dbname with a drive alias
// ----------------------------------------------------------------------------
//
void CMPXDbManager::ReplaceDriveAlias(
    TDes& aQuery,
    const TDesC& aAlias)
    {
//  MPX_FUNC("CMPXDbManager::ReplaceDriveAlias");

    TInt dbnamePos(aQuery.Find(KDBNameToken));
    while (dbnamePos != KErrNotFound)
        {
        aQuery.Delete(dbnamePos, KDBNameToken().Length());
        aQuery.Insert(dbnamePos, aAlias);
        dbnamePos = aQuery.Find(KDBNameToken);
        }
    }

// ----------------------------------------------------------------------------
// Replaces :dbname with a drive alias
// ----------------------------------------------------------------------------
//
void CMPXDbManager::ReplaceDriveAlias(
    TDes& aQuery,
    const TDesC& aAlias,
    const TDesC& aToKen)
    {
    
    TInt dbnamePos(aQuery.Find(aToKen));
    while (dbnamePos != KErrNotFound)
        {
        aQuery.Delete(dbnamePos, aToKen.Length());
        aQuery.Insert(dbnamePos, aAlias);
        dbnamePos = aQuery.Find(aToKen);
        }
    }

// ----------------------------------------------------------------------------
// Removes :dbname
// ----------------------------------------------------------------------------
//
void CMPXDbManager::RemoveDriveAlias(
    TDes& aQuery)
    {
    MPX_FUNC("CMPXDbManager::RemoveDriveAlias");

    TInt dbnamePos(aQuery.Find(KDBNameToken));
    while (dbnamePos != KErrNotFound)
        {
        aQuery.Delete(dbnamePos, KDBNameToken().Length() + 1);
        dbnamePos = aQuery.Find(KDBNameToken);
        }
    }


// ----------------------------------------------------------------------------
// Removes :dbname
// ----------------------------------------------------------------------------
//
void CMPXDbManager::RemoveDriveAlias(
    TDes& aQuery,const TDesC& aToKen)
    {
    MPX_FUNC("CMPXDbManager::RemoveDriveAlias");

    TInt dbnamePos(aQuery.Find(aToKen));
    while (dbnamePos != KErrNotFound)
        {
        aQuery.Delete(dbnamePos, aToKen.Length() + 1);
        dbnamePos = aQuery.Find(aToKen);
        }
    }


// ----------------------------------------------------------------------------
// CMPXDbManager::CheckDiskSpaceL
// ----------------------------------------------------------------------------
//
EXPORT_C void CMPXDbManager::CheckDiskSpaceL(
    TInt aDrive)
    {
    MPX_FUNC("CMPXDbManager::CheckDiskSpaceL");
    
    // LTAN-7GH6BZ, crash if eject memory card when adding song to existing playlist
    // due to special timing issue, it is possible drive number is -1 and create a
    // panic when use for TDriveUnit
    MPX_DEBUG2("aDrive = %d", aDrive);
    
    if (aDrive < 0)
        {
        MPX_DEBUG1("invalid driveId, leave with KErrNotReady");
        User::Leave(KErrNotReady);
        }
    
    EnsureDiskSpaceL(aDrive);
    }
    
// ----------------------------------------------------------------------------
// Regenerate all databases.
// ----------------------------------------------------------------------------
//
EXPORT_C void CMPXDbManager::RegenerateAllDatabasesL()
    {
    MPX_DEBUG1("CMPXDbManager::RegenerateAllDatabasesL Enter");
    ResetPreparedQueries(); //just in case ...
    TInt handles(iDatabaseHandles.Count());
    for (TInt i = 0; i < handles; ++i)
        {
        iDatabaseHandles[i].iOpen = EFalse; //attach will open them again
        }    
    iDatabase.Close(); //close the database before deleting the file
    iInitialized = EFalse;

    MPX_DEBUG1("RegenerateAllDatabasesL: Regenerating main DB on C:");
    HBufC * filename = CreateFilenameL(EDriveC);
    CleanupStack::PushL(filename);
    RSqlDatabase::Delete(*filename);
    TDriveUnit cdrive(KRootDrive());
    CreateDatabaseL(cdrive);
    User::LeaveIfError(iDatabase.Open(*filename)); // will set handle status later
    CleanupStack::PopAndDestroy(filename);
    MPX_DEBUG1("RegenerateAllDatabasesL: DB regeneration complete");
    
    // Recreate all attached drives
    TInt count(iDatabaseHandles.Count());
    for (TInt i = 0; i < count; ++i)
        {
        if (iDatabaseHandles[i].iDrive != EDriveC)
            {
            MPX_DEBUG2("RegenerateAllDatabasesL: Regenerating DB on %d",iDatabaseHandles[i].iDrive);
            TVolumeInfo volumeInfo; 
            TInt err = iFs.Volume(volumeInfo,iDatabaseHandles[i].iDrive);
            if(err != KErrNone)
                {
                continue; //if drive is not currently accessible, skip
                }
            filename = CreateFilenameL(iDatabaseHandles[i].iDrive);
            CleanupStack::PushL(filename);
            MPX_DEBUG1("RegenerateAllDatabasesL: Detaching DB");
            err = iDatabase.Detach(*(iDatabaseHandles[i].iAliasname)); //ignore the error if any
            MPX_DEBUG2("RegenerateAllDatabasesL: Detached[err=%d]; Deleting DB",err);
            err = RSqlDatabase::Delete(*filename);
            MPX_DEBUG2("RegenerateAllDatabasesL: Deleted[err=%d]; Creating new DB",err);
            TDriveUnit drive(iDatabaseHandles[i].iDrive);
            CreateDatabaseL(drive);
            MPX_DEBUG1("RegenerateAllDatabasesL: Attaching new DB");
            AttachDatabaseL( i );    
            MPX_DEBUG1("RegenerateAllDatabasesL: DB regeneration complete");
            CleanupStack::PopAndDestroy(filename);
            }
        else
            {
            iDatabaseHandles[i].iOpen = ETrue; //if we got here it is opened
            }
        }
    iInitialized = ETrue;
    MPX_DEBUG1("CMPXDbManager::RegenerateAllDatabasesL Exit");
    }    

// ----------------------------------------------------------------------------
// CMPXDbManager::DoRecreateDatabaseL
// ----------------------------------------------------------------------------
//
void CMPXDbManager::DoRecreateDatabaseL(HBufC * aFilename)
    {
    RSqlDatabase database;
    CleanupClosePushL(database);

    User::LeaveIfError(database.Open(aFilename->Des()));

    TInt count(iTables.Count());
    for (TInt i = 0; i < count; ++i)
        {
        iTables[i]->DropTableL(database);
        iTables[i]->CreateTableL(database, EFalse);
        }
    CleanupStack::PopAndDestroy(&database);
    }

// ----------------------------------------------------------------------------
// CMPXDbManager::ExecuteSqlStatement
// ----------------------------------------------------------------------------
//
TInt CMPXDbManager::ExecuteSqlStatement(RSqlDatabase& aDatabase,const TDesC& aStatement)
    {
    MPX_FUNC("CMPXDbManager::ExecuteSqlStatement");
    TInt result( KErrNone );
    RSqlStatement sqlStatement;
    //Prepare and execute SQL statement
    result = sqlStatement.Prepare(aDatabase, aStatement);
    if (result == KErrNone)
        {
        result = sqlStatement.Exec();
        //If the database schema was changed or the session expired repeat all the steps
        if((result == KSqlErrStmtExpired) || (result == KSqlErrSchema))
            {
            sqlStatement.Close();
            result = sqlStatement.Prepare(aDatabase, aStatement);
            if (result == KErrNone)
                {
                result = sqlStatement.Exec();
                }
            }
        sqlStatement.Close();
        }
    return result;
    }

#ifdef _DEBUG

// ----------------------------------------------------------------------------
// Returns the number of columns from a specified SQL statement
// ----------------------------------------------------------------------------
//
TInt CMPXDbManager::GetColumnCountL(
    RSqlStatement& aStatement)
    {
    TInt columnCount(0);

// Using TSqlRowSetUtil causes linker errors on ARMv5 UDEB
// Enabling this functionality for WINSCW UDEB only
// PREQ2536 the files sqlrowsetutil.h and sqlrowsetutil.cpp has been removed
//#ifdef __WINSCW__
//
//    HBufC* headers = TSqlRowSetUtil::GetDeclColumnTypesL(aStatement);
//    CleanupStack::PushL(headers);
//
//    // Count the number of semicolons to get the number of columns
//    TPtr headerPtr = headers->Des();
//    TInt location(headerPtr.Locate(';'));
//    while ((location != KErrNotFound) && (location < headers->Length()))
//        {
//        ++columnCount;
//        if (++location < headers->Length())
//            {
//            headerPtr = headers->Des().Mid(location);
//            location = headerPtr.Locate(';');
//            }
//        }
//    CleanupStack::PopAndDestroy(headers);
//
//#else
	(void)aStatement;
//#endif

    return columnCount;
    }

// ----------------------------------------------------------------------------
// Prints the table values from a specified SQL query
// ----------------------------------------------------------------------------
//
void CMPXDbManager::PrintTableValuesL(
    RSqlStatement& aStatement)
    {
    TInt columnCount(GetColumnCountL(aStatement));
    TInt err(KErrNone);
    HBufC* tableRow = HBufC::NewLC(255 * columnCount);
    TPtr tableRowPtr = tableRow->Des();

    while ((err = aStatement.Next()) == KSqlAtRow)
        {
        tableRowPtr.Zero();
        TInt error(KErrNone);
        for (TInt index = 0; (error == KErrNone) && (index < columnCount); ++index)
            {
            if (index !=0)
                {
                tableRowPtr.Append(',');
                }
            switch (aStatement.ColumnType(index))
                {
                case ESqlNull:
                    tableRowPtr.Append(_L("<NULL>"));
                    break;

                case ESqlInt:
                    {
                    tableRowPtr.AppendFormat(_L("%u"), aStatement.ColumnInt(index));
                    }
                    break;

                case ESqlInt64:
                    {
                    tableRowPtr.AppendFormat(_L("%lu"), aStatement.ColumnInt64(index));
                    }
                    break;

                case ESqlReal:
                    {
                    tableRowPtr.AppendFormat(_L("%f"), aStatement.ColumnReal(index));
                    }
                    break;

                case ESqlText:
                    {
                    TPtrC columnValue;
                    error = aStatement.ColumnText(index, columnValue);
                    if (error == KErrNone)
                        {
                        tableRowPtr.AppendFormat(_L("%S"), &columnValue);
                        }
                    }
                    break;

                case ESqlBinary:
                    {
                    TPtrC8 columnValue;
                    error = aStatement.ColumnBinary(index, columnValue);
                    if (error == KErrNone)
                        {
                        tableRowPtr.AppendFormat(_L("%S"), &columnValue);
                        }
                    }
                    break;

                default :
                    ASSERT(EFalse);
                }

            if (tableRowPtr.Length() > 255)
                {
                tableRowPtr.SetLength(255);
                MPX_DEBUG2("%S", tableRow);
                tableRowPtr.Zero();
                }
            }
        if (tableRowPtr.Length() > 0)
            {
            tableRowPtr.SetLength(Min(tableRowPtr.Length(), 255));
            MPX_DEBUG2("%S", tableRow);
            }
        }
    CleanupStack::PopAndDestroy(tableRow);
    if (err != KSqlAtEnd)
        {
        User::Leave(err);
        }
    }

// ----------------------------------------------------------------------------
// Finds all the tables on the main or attached drives
// ----------------------------------------------------------------------------
//
void CMPXDbManager::FindAllTablesL(
    const TDesC& aAlias,
    RArray<HBufC*>& aTableName)
    {
    RSqlStatement statement;
    CleanupClosePushL(statement);

    if (aAlias == KNullDesC)
        {
        statement.Prepare(iDatabase, KFindAllCDriveTablesQuery);
        }
    else
        {
        HBufC* query = KFindAllAttachedTablesQuery().AllocL();
        CleanupStack::PushL(query);
        TPtr queryPtr = query->Des();
        ReplaceDriveAlias(queryPtr, aAlias);
        statement.Prepare(iDatabase, queryPtr);
        CleanupStack::PopAndDestroy(query);
        }

    TInt err(KErrNone);

    while ((err = statement.Next()) == KSqlAtRow)
        {
        TPtrC val = statement.ColumnTextL(statement.ColumnIndex(KNameColumn));
        aTableName.AppendL(val.AllocL());
        }
    if (err != KSqlAtEnd)
        {
        User::Leave(err);
        }

    CleanupStack::PopAndDestroy(&statement);
    }

// ----------------------------------------------------------------------------
// Prints the tables on the main or attached drives
// ----------------------------------------------------------------------------
//
void CMPXDbManager::PrintTableL(
    const TDesC& aAlias,
    const TDesC& aTableName)
    {
    RSqlStatement statement;
    CleanupClosePushL(statement);

    if (aAlias == KNullDesC)
        {
        HBufC* selectQuery = HBufC::NewLC(KTableQuery().Length() + aTableName.Length());
        selectQuery->Des().Format(KTableQuery, &aTableName);
        User::LeaveIfError(statement.Prepare(iDatabase, *selectQuery));
        CleanupStack::PopAndDestroy(selectQuery);
        }
    else
        {
        HBufC* selectQuery = HBufC::NewLC(KAttachedTableQuery().Length() + aTableName.Length());
        selectQuery->Des().Format(KAttachedTableQuery, &aTableName);

        TPtr selectQueryPtr(selectQuery->Des());
        ReplaceDriveAlias(selectQueryPtr, aAlias);
        User::LeaveIfError(statement.Prepare(iDatabase, *selectQuery));

        CleanupStack::PopAndDestroy(selectQuery);
        }

    PrintTableValuesL(statement);
    CleanupStack::PopAndDestroy(&statement);
    }

#endif

// ----------------------------------------------------------------------------
// Prints all the tables on the main and attached drives
// ----------------------------------------------------------------------------
//
EXPORT_C void CMPXDbManager::PrintDatabaseL()
    {
#ifdef _DEBUG
    if (iInitialized)
        {
        // C-Drive
        RArray<HBufC*> tableNames;
        FindAllTablesL(KNullDesC(), tableNames);

        MPX_DEBUG1("### Drive C ###");

        TInt tableCount(tableNames.Count());
        for (TInt i = 0; i < tableCount; ++i)
            {
            MPX_DEBUG2("# %S #", tableNames[i]);
            MPX_TRAPD(error, PrintTableL(KNullDesC, *tableNames[i]));
            delete tableNames[i];
            if (error != KErrNone)
                {
                if (error != KErrPermissionDenied)
                    {
                    User::Leave(error);
                    }
                else
                    {
                    MPX_DEBUG1("Unable to print table");
                    }
                }
            }
        tableNames.Close();

        // Each attached drive
        TInt count(iDatabaseHandles.Count());
        for (TInt i = 0; i < count; ++i)
            {
            if (iDatabaseHandles[i].iOpen)
                {
                FindAllTablesL(iDatabaseHandles[i].iAliasname->Des(), tableNames);

                TDriveUnit driveUnit(iDatabaseHandles[i].iDrive);
                const   TDesC& name = driveUnit.Name();
                MPX_DEBUG2("### Drive %S ###", &name);

                for (TInt j = 0; j < tableCount; ++j)
                    {
                    MPX_DEBUG2("# %S #", tableNames[j]);
                    MPX_TRAPD(error, PrintTableL(iDatabaseHandles[i].iAliasname->Des(), *tableNames[j]));
                    delete tableNames[j];
                    if (error != KErrNone)
                        {
                        if (error != KErrPermissionDenied)
                            {
                            User::Leave(error);
                            }
                        else
                            {
                            MPX_DEBUG1("Unable to print table");
                            }
                        }
                    }
                tableNames.Close();
                }
            }
        }
#endif
    }

// ----------------------------------------------------------------------------
// Prints all the tables on the main and attached drives
// ----------------------------------------------------------------------------
//
EXPORT_C RFs& CMPXDbManager::Fs()
    {
    return iFs;
    }



// ---------------------------------------------------------------------------
// CMPXDbManager::IsRemoteDrive
// ---------------------------------------------------------------------------
//
EXPORT_C TBool CMPXDbManager::IsRemoteDrive(TDriveNumber aDrive)
    {
    TDriveInfo driveInfo;
    TBool isRemoteDrive(EFalse);
    if (iFs.Drive(driveInfo, aDrive) == KErrNone)
        {
        isRemoteDrive = driveInfo.iDriveAtt & KDriveAttRemote;
        }
    return isRemoteDrive;
    }

// ---------------------------------------------------------------------------
// CMPXDbManager::DoCreateDatabaseL
// ---------------------------------------------------------------------------
//
void CMPXDbManager::DoCreateDatabaseL( TDriveUnit aDrive )
    {
	MPX_FUNC( "CMPXDbManager::DoCreateDatabaseL" );
	
    RSqlDatabase database;
    CleanupClosePushL(database);

    HBufC* filename = CreateFilenameL(aDrive);
    CleanupStack::PushL(filename);
    
    // remove old databases before creating/replacing new database
    TInt driveNameLen = aDrive.Name().Length();
    
    TFileName dbFileName;

#ifdef __RAMDISK_PERF_ENABLE
    TInt index(GetDatabaseIndex((TInt)aDrive));
    if( index >= 0 && iDatabaseHandles[index].iUseRAMdb )
        {
        dbFileName.Append(iRAMDrive); // RAM
        dbFileName.Append(_L(":")); // RAM
        }
    else 
#endif //__RAMDISK_PERF_ENABLE
        {
        MPX_DEBUG1("CMPXDbManager::CreateDatabaseL - E:");
        dbFileName.Append(aDrive.Name()); //initialise with drive name
        }
        

    MPX_DEBUG2("CMPXDbManager::CreateDatabaseL - dbFileName=%S", &dbFileName);
    dbFileName.Append(KDBFilePath);  // append private path
    
    //append file name
    dbFileName.Append(filename->Right((filename->Length())- driveNameLen));     
    
    // locate the offset position where version info starts in file name
    TInt pos = dbFileName.LocateReverse('v');

    //replace version info with wildcards 
    dbFileName.Replace(pos, (dbFileName.Length()- pos), KDBFilePattern);

    CFileMan* fileManager = CFileMan::NewL(iFs);
    TInt ret = fileManager->Delete(dbFileName);
    delete fileManager;
    fileManager = NULL;
    
    // create the database now
    RSqlSecurityPolicy securityPolicy;
    CleanupClosePushL(securityPolicy);

    TSecurityPolicy policy(TSecurityPolicy::EAlwaysPass);
    securityPolicy.Create(policy);

    TSecurityPolicy schemaPolicy(TSecurityPolicy::EAlwaysPass);
    TSecurityPolicy readPolicy(TSecurityPolicy::EAlwaysPass);
    TSecurityPolicy writePolicy(TSecurityPolicy::EAlwaysPass);

    User::LeaveIfError(securityPolicy.SetDbPolicy(RSqlSecurityPolicy::ESchemaPolicy, schemaPolicy));
    User::LeaveIfError(securityPolicy.SetDbPolicy(RSqlSecurityPolicy::EReadPolicy, readPolicy));
    User::LeaveIfError(securityPolicy.SetDbPolicy(RSqlSecurityPolicy::EWritePolicy, writePolicy));

    
    const TDesC8& config = KMCSqlConfig;
    
    TBool corrupt(EFalse);
    TInt err = database.Create(filename->Des(), securityPolicy, &config);
    if (KErrAlreadyExists == err)
        {
        MPX_DEBUG1("CMPXDbManager::DoCreateDatabaseL - could not create the database");

        // the file already exists and it is corrupted
        // make sure we delete the file
        User::LeaveIfError(database.Delete(*filename));

        MPX_DEBUG1("CMPXDbManager::DoCreateDatabaseL - deleted the database");

        // try again
        err = database.Create(filename->Des(), securityPolicy, &config);

        // the database could not be opened but the file exists
        corrupt = ETrue;
        }
    User::LeaveIfError(err);

    MPX_DEBUG1("CMPXDbManager::DoCreateDatabaseL - created the database");

    CleanupStack::PopAndDestroy(&securityPolicy);

    CreateTablesL(database, corrupt);

    CleanupStack::PopAndDestroy(filename);
    CleanupStack::PopAndDestroy(&database);
    }
	
// ---------------------------------------------------------------------------
// CMPXDbManager::GetRAMDiskPath
// ---------------------------------------------------------------------------
//
TInt CMPXDbManager::GetRAMDiskPath()
    {
    TInt error = KErrNotSupported;
#ifdef __RAMDISK_PERF_ENABLE
    MPX_DEBUG1("-->CMPXDbManager::GetRAMDiskPath");
    TDriveList driveList;
    TBool ramDriveFound = EFalse;
    TInt driveOffset = 'A';
    iRAMFolder.Zero();
    
    error = iFs.DriveList( driveList );
    if ( error == KErrNone )
        {
        for ( TInt i = 0; i < driveList.Length(); i++ )
            {
            if ( driveList[i] != 0 )
                {
                TDriveInfo info;
                TInt err = iFs.Drive( info, i );
                if ( !err && info.iType == EMediaRam )
                    {
                    iRAMDrive = driveOffset + i;
                    iRAMFolder.Append(iRAMDrive);
                    iRAMFolder.Append(_L(":"));
                    iRAMFolder.Append(KDBFilePath);
                    ramDriveFound = ETrue;
                    MPX_DEBUG2("RAMDisk path=%S", &iRAMFolder);
                    break;
                    }
                }
            }
        
        // Check if ram drive is found.
        if ( !ramDriveFound )
            {
            error = KErrNotFound;
            }
        }
    MPX_DEBUG2("CMPXDbManager::GetRAMDiskPath Get DriveList error=%d", error);
    MPX_DEBUG1("<--CMPXDbManager::GetRAMDiskPath");
#endif //__RAMDISK_PERF_ENABLE
    return error;
    }

// ---------------------------------------------------------------------------
// CMPXDbManager::IsRamDiskSpaceAvailable
// ---------------------------------------------------------------------------
//
TBool CMPXDbManager::IsRamDiskSpaceAvailable()
    {

#ifdef __RAMDISK_PERF_ENABLE

    MPX_DEBUG1("-->CMPXDbManager::IsDiskSpaceAvailable" );
    TInt driveIndex;
    RFs::CharToDrive(iRAMDrive, driveIndex);
    TVolumeInfo vol;
    TInt err = iFs.Volume( vol, driveIndex );
    if ( err == KErrNone )
        {
        MPX_DEBUG2("CMPXDbManager::IsRamDiskSpaceAvailable Free in bytes =%Lu", vol.iFree);
        if ( vol.iFree > KMPMinimumRAMSizeToRun )
            {
            MPX_DEBUG1("CMPXDbManager::IsRamDiskSpaceAvailable Ok to copy");
            return ETrue;
            }
        MPX_DEBUG1("CMPXDbManager::IsRamDiskSpaceAvailable NOT Ok to copy");
        return EFalse;
        }
    
    MPX_DEBUG2("CMPXDbManager::IsRamDiskSpaceAvailable Disk Not available to use. %d", err);
    MPX_DEBUG1("<--CMPXDbManager::IsDiskSpaceAvailable");

#endif //__RAMDISK_PERF_ENABLE

    return EFalse;
    }


// ---------------------------------------------------------------------------
// CMPXDbManager::BlockDiskSpaceL
// ---------------------------------------------------------------------------
//
TBool CMPXDbManager::BlockDiskSpace( TInt aIndex, TBool aIsMTPInUse )
    {
#ifdef __RAMDISK_PERF_ENABLE

    MPX_DEBUG2("-->CMPXDbManager::BlockDiskSpaceL %d", aIndex );
    DatabaseHandle & database = iDatabaseHandles[aIndex];    
    // if current DB size can not fit in RAM, abort now
    TInt ramDrive;
    RFs::CharToDrive(iRAMDrive, ramDrive);
    TVolumeInfo vol;
    TInt err = iFs.Volume( vol, ramDrive );
    TEntry origDb;
    iFs.Entry( *database.iOrigFullFilePath, origDb );
    if ( vol.iFree <= origDb.iSize + KMPMinimumRAMSizeToRun )
        {
        MPX_DEBUG1("-->CMPXDbManager::BlockDiskSpaceL Not enough even for copy original DB file, leave" );
        return EFalse;
        }

    // ensure you have the disk volume and database
    err = iFs.Volume( vol, database.iDrive );
    if (err != KErrNone) 
        {
        MPX_DEBUG2("CMPXDbManager::BlockDiskSpaceL Volume not available on drive %d", database.iDrive);
        return EFalse;
        }

    // Check if the drive has enough space to block
    MPX_DEBUG2("CMPXDbManager::BlockDiskSpaceL Disk total free space in bytes =%Lu", vol.iFree);
    TInt64 blockingSize( CalculateInitalDummyDBSize( vol, origDb.iSize, aIsMTPInUse ));
    MPX_DEBUG2("CMPXDbManager::BlockDiskSpaceL Disk blocking size =%Lu", blockingSize);
    if ( vol.iFree <= blockingSize + 1*KMPMegaByte )
        {
        MPX_DEBUG1("CMPXDbManager::BlockDiskSpaceL NOk to block");
        return EFalse;
        }

    // Create and resize the dummy file
    TChar ch;
    RFs::DriveToChar(database.iDrive, ch );
    database.iDummyFilePath.Format( KDummyDbFile, (TUint)ch);
    RFile dummyDb;
    err = dummyDb.Replace( iFs, database.iDummyFilePath, EFileWrite );
    if (err != KErrNone) 
        {
        MPX_DEBUG2("CMPXDbManager::BlockDiskSpaceL Can't open dummy file %d", err);
        database.iDummyFilePath.Zero();
        return EFalse;
        }
    err = dummyDb.SetSize( blockingSize );
    if ( err )
        {
        MPX_DEBUG2("CMPXDbManager::BlockDiskSpaceL Can't resize dummy file %d", err);
        dummyDb.Close();
        RemoveDummyFile(aIndex);
        return EFalse;
        }

    dummyDb.Close();
    MPX_DEBUG1("CMPXDbManager::BlockDiskSpaceL Ok to block");
    MPX_DEBUG1("<--CMPXDbManager::BlockDiskSpace");

    return ETrue;
#else
    return EFalse;
#endif //__RAMDISK_PERF_ENABLE
    }


// ---------------------------------------------------------------------------
// CMPXDbManager::CalculateInitalDummyDBSizeL
//
//a) MTP case
//-------------
//        totalNumOfSongsCanFit = <disk free space> / 2 MB;
//        metadataSize = totalNumOfSongsCanFit * 3000B 
//        estimatedDBSize = metadataSize + <orig DB size>;
//        dummyDBSize = MIN (iMaximumAllowedRAMDiskSpaceToCopy , estimatedDBSize )

//b) Harvesting case
//-------------------
//        totalNumOfSongsCanFit = <disk total size>/ 2 MB
//        metadataSize = totalNumOfSongsCanFit * 3000B 
//        estimatedSize = metadataSize+ <orig DB size>
//        freeDiskSpace = <disk free space> - 1 MB
//        dummyDBSize = MIN (freeDiskSpace, iMaximumAllowedRAMDiskSpaceToCopy , estimatedSize);
//
// ---------------------------------------------------------------------------
//
TInt64 CMPXDbManager::CalculateInitalDummyDBSize( const TVolumeInfo& aVol, TInt aOrigDbSize, TBool aIsMTPInUse )
    {
#ifdef __RAMDISK_PERF_ENABLE
    MPX_DEBUG1("-->CMPXDbManager::CalculateInitalDummyDBSize");

    if ( aIsMTPInUse )
        {
        TInt64 totalNumOfSongsCanFit = aVol.iFree / KMPEstimatedSongInBytes;
        MPX_DEBUG2("-->CMPXDbManager::CalculateInitalDummyDBSize aVol.iFree=%Lu", aVol.iFree );
        MPX_DEBUG2("-->CMPXDbManager::CalculateInitalDummyDBSize totalNumOfSongsCanFit=%Lu", totalNumOfSongsCanFit );
        TInt64 estimatedSize = totalNumOfSongsCanFit * (TInt64) KMPEstimatedSizePerDBEntry + aOrigDbSize;
        MPX_DEBUG2("-->CMPXDbManager::CalculateInitalDummyDBSize (MTP case) estimated DB size from calculation=%Lu", estimatedSize );
        if ( estimatedSize > iMaximumAllowedRAMDiskSpaceToCopy )
            {
            MPX_DEBUG2("<--CMPXDbManager::CalculateInitalDummyDBSize returned iMaximumAllowedRAMDiskSpaceToCopy %d", iMaximumAllowedRAMDiskSpaceToCopy);
            return iMaximumAllowedRAMDiskSpaceToCopy;
            }
        else
            {
            MPX_DEBUG2("<--CMPXDbManager::CalculateInitalDummyDBSize returned %Lu", estimatedSize );
            return estimatedSize;
            }
        }
    else
        {
        TInt64 totalNumOfSongsCanFit = aVol.iSize / KMPEstimatedSongInBytes;
        TInt64 estimatedSize = totalNumOfSongsCanFit * (TInt64) KMPEstimatedSizePerDBEntry + aOrigDbSize;
        MPX_DEBUG2("-->CMPXDbManager::CalculateInitalDummyDBSize estimated DB size from calculation=%Lu", estimatedSize );
        if ( estimatedSize > iMaximumAllowedRAMDiskSpaceToCopy )
            {
            MPX_DEBUG1("<--CMPXDbManager::CalculateInitalDummyDBSize");
            // If estimated size is larger than expected free RAM size, 
            // and if the RAM size is larger than free disk space,
            // then use free disk space. 1*KMPMegaByte prevent MP to use up all diskspace
            //return iMaximumAllowedRAMDiskSpaceToCopy > aVol.iFree - 1*KMPMegaByte  
            //    ? aVol.iFree - 1*KMPMegaByte : iMaximumAllowedRAMDiskSpaceToCopy;
            return iMaximumAllowedRAMDiskSpaceToCopy;
            }
        else
            {
            MPX_DEBUG1("<--CMPXDbManager::CalculateInitalDummyDBSize");
            // If estimated size is larger than disk free size, use free diskspace size,            
            //return estimatedSize > aVol.iFree - 1*KMPMegaByte
            //    ? aVol.iFree - 1*KMPMegaByte : estimatedSize;
            return estimatedSize;
            }
        }
    
#endif //__RAMDISK_PERF_ENABLE    
    }
    

// ---------------------------------------------------------------------------
// CMPXDbManager::GetDatabaseIndex
// ---------------------------------------------------------------------------
//
TInt CMPXDbManager::GetDatabaseIndex(TInt aDrive) 
    {
#ifdef __RAMDISK_PERF_ENABLE
    MPX_DEBUG2("-->CMPXDbManager::GetDatabaseIndex %d", aDrive );
    TInt count(iDatabaseHandles.Count());
    for (TInt i = 0; i < count; ++i)
        {
        if ( iDatabaseHandles[i].iDrive == aDrive )
            {
            return i;
            }
        }    
#endif //__RAMDISK_PERF_ENABLE    
    MPX_DEBUG1("<--CMPXDbManager::GetDatabaseIndex returned -1");
    return -1;
    }


// ---------------------------------------------------------------------------
// CMPXDbManager::EnsureRamSpaceL
// ---------------------------------------------------------------------------
//
EXPORT_C void CMPXDbManager::EnsureRamSpaceL() 
    {
#ifdef __RAMDISK_PERF_ENABLE
    MPX_DEBUG1("-->CMPXDbManager::EnsureRamSpaceL");

    if ( iRAMInUse )
        {
        TVolumeInfo vol;
        TInt driveIndex;
        RFs::CharToDrive( iRAMDrive, driveIndex );

        TInt errRAM = iFs.Volume( vol, driveIndex );
        if ( errRAM == KErrNone && vol.iFree < KMPMinimumRAMSizeToRun )
            {
            // RAM not enough, copy back to normal drive and continue to harvest.
            MPX_DEBUG1("CMPXDbManager::EnsureRamSpaceL RAM diskspace is full, copy dbs back");
            CopyDBsFromRamL();
            }
        else
            {
            TInt size=0;
            TInt err = GetTotalRamDatabasesSizeL(size);
            if ( err || (size > iMaximumAllowedRAMDiskSpaceToCopy) )
                {
                // Databases using too much RAM space, copy back to normal drive and continue to harvest.
                if ( err )
                    {
                    MPX_DEBUG2("CMPXDbManager::EnsureRamSpaceL Get DBs Size Err = %d, copy dbs back", err);
                    }
                else
                    {
                    MPX_DEBUG2("CMPXDbManager::EnsureRamSpaceL DBs using too much RAM space size = %d, copy dbs back", size);
                    }
                CopyDBsFromRamL();
                }
            }
        }
    MPX_DEBUG1("<--CMPXDbManager::EnsureRamSpaceL");
#endif //__RAMDISK_PERF_ENABLE    
    }


// ---------------------------------------------------------------------------
// CMPXDbManager::EnsureDiskSpaceL
// ---------------------------------------------------------------------------
//
void CMPXDbManager::EnsureDiskSpaceL(TInt aDrive) 
    {
    MPX_DEBUG2("-->CMPXDbManager::EnsureDiskSpaceL for drive %d", aDrive);
    // handle the case of C drive
    TDriveUnit drive(aDrive);
    TDriveUnit cdrive(KRootDrive());

    if(drive == cdrive)
        {
        if (SysUtil::DiskSpaceBelowCriticalLevelL(&iFs, 0, aDrive))
            {
            MPX_DEBUG1("CMPXDbManager::EnsureDiskSpaceL Error diskspace full");
            User::Leave(KErrDiskFull);
            }

        return;
        }

    // handle other drives (eg. removable EDriveE)
    TInt count(iDatabaseHandles.Count());
    for (TInt i = 0; i < count; ++i)
        {
        DatabaseHandle& database = iDatabaseHandles[i];
        if (((KDbManagerAllDrives == aDrive) ||
            (aDrive == database.iDrive)) &&
            database.iOpen
#ifdef __RAMDISK_PERF_ENABLE
            && !database.iUseRAMdb
#endif
            )
            {
            if (SysUtil::DiskSpaceBelowCriticalLevelL(&iFs, 0,
                database.iDrive))
                {
                MPX_DEBUG1("CMPXDbManager::EnsureDiskSpaceL Error diskspace full");
                User::Leave(KErrDiskFull);
                }
            }

        if (aDrive == database.iDrive)
            {
            // exit if just one drive to check
            break;
            }
        }
    MPX_DEBUG1("<--CMPXDbManager::EnsureDiskSpaceL");
    }


// ---------------------------------------------------------------------------
// CMPXDbManager::DoBackupDBs
// ---------------------------------------------------------------------------
//
/*EXPORT_C void CMPXDbManager::BackupDBsL()
    {
#ifdef __RAMDISK_PERF_ENABLE
    MPX_DEBUG1("-->CMPXDbManager::BackupDBsL");

    TInt transactionCount = iTransactionCount;
    if (iTransactionCount > 0) 
        {
        iTransactionCount = 0;
        DoCommitL();
        }
    
    TInt count(iDatabaseHandles.Count());
    for (TInt i = 0; i < count && iDatabaseHandles[i].iUseRAMdb ; ++i)
        {
        CloseDatabaseAtIndexL( i );            

        TInt err= BaflUtils::CopyFile(iFs, 
            iDatabaseHandles[i].iTargetFullFilePath->Des(), 
            iDatabaseHandles[i].iOrigFullFilePath->Des());

        MPX_DEBUG2("CMPXDbManager::BackupDBsL err = %d", err);     

        OpenDatabaseAtIndexL( i );      
        }
        
    if (transactionCount > 0) 
        {
        DoBeginL();
        iTransactionCount = transactionCount;
        }
    MPX_DEBUG1("<--CMPXDbManager::BackupDBsL");
#endif //__RAMDISK_PERF_ENABLE    
    }*/
    
// ---------------------------------------------------------------------------
// CMPXDbManager::GetTotalDatabasesSize
// ---------------------------------------------------------------------------
//
TInt CMPXDbManager::GetTotalDatabasesSize(TInt& aSize)
    {
    MPX_FUNC("CMPXDbManager::GetTotalDatabasesSize");
    TInt err = KErrNotSupported;
#ifdef __RAMDISK_PERF_ENABLE
    TInt size=0;
    TInt count(iDatabaseHandles.Count());
    err = KErrNone;
    for ( TInt i = 0; i < count ; ++i )
        {
        // Generate database name.
        TFileName dbFilename;
        TDriveUnit drive(iDatabaseHandles[i].iDrive);
        dbFilename.Append(drive.Name());
        dbFilename.Append(KDBFilePath);
        TFileName filename;            
        filename.Format(KSecurePath, User::Identity().iUid, iDbFile); //x:\private\10281e17\[sldfdsf]mpxv2_5.db
        dbFilename.Append(filename);
        MPX_DEBUG2("CMPXDbManager::GetTotalDatabasesSize - Database name = %S", &dbFilename);
        TEntry entry;
        err = iFs.Entry( dbFilename, entry );
        if (err == KErrNotFound || err == KErrNotReady )
            {
            MPX_DEBUG3("CMPXDbManager::GetTotalDatabasesSize - Ignored %S, error = %d", &dbFilename, err);
            err = KErrNone;
            continue;
            }
        if ( err != KErrNone )
            {
            break;
            }
        MPX_DEBUG3("CMPXDbManager::GetTotalDatabasesSize - Size of Db %S = %d", &dbFilename, entry.iSize);
        // sum up size
        size += entry.iSize;
        }
    aSize = size;
    MPX_DEBUG2("CMPXDbManager::GetTotalDatabasesSize - Total Size of Dbs = %d", size);
    
#endif //__RAMDISK_PERF_ENABLE    
    MPX_DEBUG2("CMPXDbManager::GetTotalDatabasesSize - Return err = %d", err);
    return err;
    }
    
// ---------------------------------------------------------------------------
// CMPXDbManager::GetTotalRamDatabasesSize
// ---------------------------------------------------------------------------
//
TInt CMPXDbManager::GetTotalRamDatabasesSizeL(TInt& aSize)
    {
    MPX_FUNC("CMPXDbManager::GetTotalRamDatabasesSize");
    TInt err = KErrNotSupported;
#ifdef __RAMDISK_PERF_ENABLE
    TInt size=0;
    TInt count(iDatabaseHandles.Count());
    err = KErrNone;
    for ( TInt i = 0; i < count ; ++i )
        {
        // make sure this db is in ram drive.
        if ( !iDatabaseHandles[i].iUseRAMdb )
            {
            continue;
            }
        // Generate database name.
        TFileName dbFilename;
        dbFilename.Append(iRAMFolder);
        TBuf<2> d;
        TDriveUnit drive(iDatabaseHandles[i].iDrive);
        d.Append(drive.Name());
        HBufC* temp = HBufC::NewLC(KMaxFileName);
        temp->Des().Append(d.Left(1));
        temp->Des().Append(iDbFile->Des());
        TFileName filename;            
        filename.Format(KSecurePath, User::Identity().iUid, temp);
        CleanupStack::PopAndDestroy(temp);
        dbFilename.Append(filename);
        MPX_DEBUG2("CMPXDbManager::GetTotalRamDatabasesSizeL - Database name = %S", &dbFilename);
        TEntry entry;
        err = iFs.Entry( dbFilename, entry );
        if ( (err != KErrNone) && (err != KErrNotFound) )
            {
            break;
            }
        MPX_DEBUG3("CMPXDbManager::GetTotalRamDatabasesSizeL - Size of Db %S = %d", &dbFilename, entry.iSize);
        // sum up size
        size += entry.iSize;
        }
    aSize = size;
    MPX_DEBUG2("CMPXDbManager::GetTotalRamDatabasesSizeL - Total Size of Dbs = %d", size);
#endif //__RAMDISK_PERF_ENABLE    
    MPX_DEBUG2("CMPXDbManager::GetTotalRamDatabasesSizeL - Return err = %d", err);
    return err;
    }

// ----------------------------------------------------------------------------
// Creates the absolute database filename on a specified drive.
// ----------------------------------------------------------------------------
//
HBufC* CMPXDbManager::CreateFullFilenameL(TDriveUnit aDrive)
    {
    MPX_FUNC("CMPXDbManager::CreateFullFilenameL");

    HBufC* filename = HBufC::NewL(KMaxFileName);
    const TDesC& securefilePath = KSecureFilePath;
    TDriveUnit cdrive(KRootDrive());

#ifdef __RAMDISK_PERF_ENABLE
    TInt index(GetDatabaseIndex((TInt)aDrive));    
    if ( index >=0 && iDatabaseHandles[index].iUseRAMdb && aDrive != cdrive )
        {
        MPX_DEBUG1("CMPXDbManager::CreateFullFilenameL - use RAMDisk");
        TFileName path;
        path.Append(iRAMDrive);
        path.Append(_L(":"));
        path.Append(KDBFilePath);
        TBuf<2> d;
        d.Append(aDrive.Name());
        TFileName temp;
        temp.Append(d.Left(1)); // attach original drive name
        temp.Append(iDbFile->Des()); 
        filename->Des().Format(securefilePath, &path, User::Identity().iUid, &temp);
        MPX_DEBUG3("CMPXDbManager::CreateFullFilenameL - path=%S filename=%S", &path, filename);
        }
    else
#endif //__RAMDISK_PERF_ENABLE
        {
        MPX_DEBUG1("CMPXDbManager::CreateFullFilenameL - use normal drive");
        TFileName dbPath;
        dbPath.Append(aDrive.Name());
        dbPath.Append(KDBFilePath);
        filename->Des().Format(securefilePath, &dbPath, User::Identity().iUid, iDbFile);
        }
    
    MPX_DEBUG2("CMPXDbManager::CreateFullFilenameL filename = %S", filename); 
    return filename;
    }

// End of File
