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


// INCLUDE FILES
#include <bautils.h>
#include <caf/data.h>
#include <caf/virtualpathptr.h>
#include <hash.h>
#include <apgcli.h>
#include <apmstd.h>
#include <sqldb.h>

#include <mpxmediageneraldefs.h>
#include <mpxmediamusicdefs.h>
#include <mpxmediaaudiodefs.h>
#include <mpxmediadrmdefs.h>
#include <mpxmediacollectiondetaildefs.h>
#include <mpxmedia.h>
#include <mpxmediaarray.h>
#include <mpxlog.h>

#include "mpxdbcommonstd.h"
#include "mpxdbcommondef.h"
#include "mpxdbcommonutil.h"

// CONSTANTS
_LIT(KPathStart, ":\\");

// ============================ FILE EXTENSION TO MIME MAP ==============================

// ----------------------------------------------------------------------------------------------------------
// Statically allocated Mime Map
// ----------------------------------------------------------------------------------------------------------
//

_LIT( KExtensionAac,    "aac" );
_LIT( KExtensionAif,    "aif"); 
_LIT( KExtensionAifc,   "aifc"); 
_LIT( KExtensionAiff,   "aiff");
_LIT( KExtensionAmr,    "amr" );
_LIT( KExtensionAu,     "au" );
_LIT( KExtensionAwb,    "awb" );
_LIT( KExtensionMid,    "mid" );
_LIT( KExtensionMidi,   "midi" );
_LIT( KExtensionMka,    "mka" );
_LIT( KExtensionMp3,    "mp3" );
_LIT( KExtensionOgg,    "ogg");
_LIT( KExtensionRa,     "ra"); 
_LIT( KExtensionRam,    "ram"); 
_LIT( KExtensionRmi,    "rmi"); 
_LIT( KExtensionSnd,    "snd" );
_LIT( KExtensionSpMid,  "spmid" );
_LIT( KExtensionWav,    "wav" );
_LIT( KExtensionWma,    "wma" );

_LIT8( KMimeTypeAac,      "audio/aac" );
_LIT8( KMimeTypeAiff,     "audio/x-aiff");
_LIT8( KMimeTypeAmr,      "audio/amr" );
_LIT8( KMimeTypeAu,       "audio/au" );
_LIT8( KMimeTypeAwb,      "audio/amr-wb" );
_LIT8( KMimeTypeBasic,    "audio/basic");
_LIT8( KMimeTypeMatroska, "audio/x-matroska");
_LIT8( KMimeTypeMid,      "audio/mid");
_LIT8( KMimeTypeMidi,     "audio/midi" );
_LIT8( KMimeTypeMpeg,     "audio/mpeg" );
_LIT8( KMimeTypeOgg,      "audio/ogg");
_LIT8( KMimeTypeReal,     "audio/x-pn-realaudio");
_LIT8( KMimeTypeSpMidi,   "audio/sp-midi" );
_LIT8( KMimeTypeWav,      "audio/wav" ); 
_LIT8( KMimeTypeWma,      "audio/x-ms-wma");

struct TMimeMapItem {
	const TDesC  * iExt;
	const TDesC8 * iType;
};

// We need to explicitly cast here as LitC::operator& requires writable DLL data (even though it is just a cast)
#define MIME_MAP_ITEM(ext,type) { &REINTERPRET_CAST(const TDesC&, ext), &REINTERPRET_CAST(const TDesC8&, type) }

// THIS ARRAY MUST BE SORTED BY EXTENSION
static const TMimeMapItem KMimeMap [] = {
    MIME_MAP_ITEM( KExtensionAac,   KMimeTypeAac),
    MIME_MAP_ITEM( KExtensionAif,   KMimeTypeAiff ),
    MIME_MAP_ITEM( KExtensionAifc,  KMimeTypeAiff ),
    MIME_MAP_ITEM( KExtensionAiff,  KMimeTypeAiff ),
    MIME_MAP_ITEM( KExtensionAmr,   KMimeTypeAmr ),
    MIME_MAP_ITEM( KExtensionAu,    KMimeTypeAu ), // KMimeTypeAudioBasic?  "audio/x-au"?
    MIME_MAP_ITEM( KExtensionAwb,   KMimeTypeAwb ),
    MIME_MAP_ITEM( KExtensionMid,   KMimeTypeMidi ),
    MIME_MAP_ITEM( KExtensionMidi,  KMimeTypeMidi ),
    MIME_MAP_ITEM( KExtensionMka,   KMimeTypeMatroska ),
    MIME_MAP_ITEM( KExtensionMp3,   KMimeTypeMpeg ),
    MIME_MAP_ITEM( KExtensionOgg,   KMimeTypeOgg ),
    MIME_MAP_ITEM( KExtensionRa,    KMimeTypeReal ),
    MIME_MAP_ITEM( KExtensionRam,   KMimeTypeReal ),
    MIME_MAP_ITEM( KExtensionRmi,   KMimeTypeMid ),
    MIME_MAP_ITEM( KExtensionSnd,   KMimeTypeBasic ),
    MIME_MAP_ITEM( KExtensionSpMid, KMimeTypeSpMidi ),
    MIME_MAP_ITEM( KExtensionWav,   KMimeTypeWav ), // "audio/x-wav"?
    MIME_MAP_ITEM( KExtensionWma,   KMimeTypeWma )
};

// ----------------------------------------------------------------------------------------------------------
// Look for Mime Type from map by file extension
// Returns NULL if file extension is not known
// ----------------------------------------------------------------------------------------------------------
//
static const TDesC8 * FindMimeTypeFromMap ( const TDesC& aFilename )
    {
    // extract extension
   	TPtrC extension;
    TInt pos = aFilename.LocateReverseF( '.' );
    if ( pos < 0  || ++pos >= aFilename.Length() )
        {
        return NULL;
        }
    extension.Set( aFilename.Mid( pos ) );

    // binary search from Mime Map
    TUint begin = 0;
    TUint end = sizeof KMimeMap / sizeof (TMimeMapItem);
    while (begin < end)
        {
        TUint at = (begin + end) / 2;
        const TMimeMapItem & item = KMimeMap[at];
        TInt r = item.iExt->CompareF(extension);
        if (r == 0)
            {
            return item.iType;
            }
        else if (r > 0)
            {
            end = at;
            }
        else
            {
            begin = at + 1;
            }
        }
    return NULL;
}

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

// ----------------------------------------------------------------------------------------------------------
// Set HBufC data member.
// ----------------------------------------------------------------------------------------------------------
//
EXPORT_C TInt MPXDbCommonUtil::SetHBuf(
    HBufC*& aBuf,
    const TDesC* aSource,
    TInt aMaxLen /*= -1*/)
    {
    TInt ret( KErrNone );
    delete aBuf;
    aBuf = NULL;

    if (aSource)
        {
        if (aMaxLen != -1 && aSource->Length() > aMaxLen)
            {
            aBuf = aSource->Left(aMaxLen).Alloc();
            ret = KErrOverflow;
            }
        else
            {
            aBuf = aSource->Alloc();
            }
        }
    else
        {
        aBuf = HBufC::New(0);
        }

    if (!aBuf)
        {
        ret = KErrNoMemory;
        }

    return ret;
    }

// ----------------------------------------------------------------------------------------------------------
// Replace single quotes `'` with two single quotes `''` as text queries are
// delimited by single quotes
// also replace 0x00 and '\t' as they will cause crash in SQLite and UI respectively
// ----------------------------------------------------------------------------------------------------------
//
EXPORT_C void MPXDbCommonUtil::FindAndReplaceSingleQuote(const TDesC& aSrc, TDes& aTrg)
    {
    TText ch;
    TInt srcLen(aSrc.Length());

    for (TInt i = 0; i < srcLen; ++i)
        {
        ch = aSrc[i];
        if((ch == 0) || (ch == TText('\t')))
            {
            aTrg.Append(TText(' '));
            }
        else
            {
            aTrg.Append(ch);
            if (ch == TText('\''))
                {
                aTrg.Append(ch);
                }
            }
        }
    }

// ----------------------------------------------------------------------------------------------------------
// Delete file from file system
// ----------------------------------------------------------------------------------------------------------
//
EXPORT_C TInt MPXDbCommonUtil::DeleteFile(
    RFs& aFs,
    const TDesC& aFile)
    {
    TInt ret(KErrNone);
    if(BaflUtils::FileExists(aFs, aFile))
        {
         ret = aFs.Delete(aFile);

        if (ret == KErrAccessDenied)
            {
            aFs.SetAtt(aFile,KEntryAttNormal,KEntryAttReadOnly);
            ret = aFs.Delete(aFile);
            }
        }
    return ret;
    }

// ----------------------------------------------------------------------------------------------------------
// Get the drive Id with a given volume unique Id
// ----------------------------------------------------------------------------------------------------------
//
EXPORT_C TInt MPXDbCommonUtil::GetDriveIdMatchVolIdL(
    RFs& aFs,
    TUint aVolumeId)
    {
    TDriveList driveList;
    TBool found(EFalse);
    TInt driveNum(EDriveA);

    User::LeaveIfError(aFs.DriveList(driveList));
    for (; driveNum <= EDriveZ; ++driveNum)
        {
        if (driveList[driveNum])
            {
            TVolumeInfo volInfo;

            if ((aFs.Volume(volInfo, driveNum) == KErrNone) &&
                (volInfo.iUniqueID == aVolumeId))
                {
                found = ETrue;
                break;
                }
            }
        }

    if (!found)
        {
        driveNum = KErrNotFound;
        }

    return driveNum;
    }

// ----------------------------------------------------------------------------------------------------------
// Get the volume Id with a given drive Id
// ----------------------------------------------------------------------------------------------------------
//
EXPORT_C TUint MPXDbCommonUtil::GetVolIdMatchDriveIdL(
    RFs& aFs,
    TInt aDriveId)
    {
    TUint volId (0);
    TVolumeInfo volInfo;
    TInt err = aFs.Volume(volInfo, aDriveId);
    if (err == KErrNone)
        {
        volId = volInfo.iUniqueID;
        }
    else if (err == KErrNotReady)
        {
        volId = 0;
        }
    else
        {
        User::Leave(err);
        }

    return volId;
    }

// ----------------------------------------------------------------------------
// Generate a 32bits Unique Id with MD5
// ----------------------------------------------------------------------------
//
EXPORT_C TUint32 MPXDbCommonUtil::GenerateUniqueIdL(
    RFs& aFs,
    TMPXGeneralCategory aTableId,
    const TDesC& aName,
    TBool aCaseSensitive)
    {
    MPX_FUNC("MPXDbCommonUtil::GenerateUniqueIdL");

    TInt extractPos(0);

    if( aName.Find(KPathStart) == KMCPathStartWithColon )
        {
        // aName is a filename
        extractPos = KMCPathStartPos;     // c:\..., include first '\' of the path
        }

    TBuf<KMaxFileName+KMCIntegerLen> fileName;
    if( extractPos )
        {
        // append volume's unique Id to path to maintain uniqueness
        TDriveUnit driveUnit( aName );
        TUint volId = MPXDbCommonUtil::GetVolIdMatchDriveIdL(aFs, driveUnit);
        if( volId )
            {
            fileName.AppendNum( volId );
            }
        else
            {
            // If media/drive doesn't exist, using whole path
            extractPos = 0;
            }
        }

    // append the path part
    fileName.Append( aName.Mid( extractPos ) );

    if( !aCaseSensitive )
        {
        fileName.LowerCase();
        }

    TInt narrowFileLen(0);
    TPtrC8 narrowFileName;
    #if defined(_UNICODE)
        narrowFileLen = fileName.Length() * 2;
        narrowFileName.Set((TUint8*)fileName.Ptr(), narrowFileLen);
    #else
        narrowFileLen = fileName.Length();
        narrowFileName.Set(fileName.Ptr(), narrowFileLen);
    #endif

    CMD5* hasher = CMD5::NewL();
    CleanupStack::PushL( hasher );
    hasher->Reset();
    TBuf8<16> hash( hasher->Hash( narrowFileName ) );   //hashed to 128bits
    CleanupStack::PopAndDestroy( hasher );

    const TText8* ptr = hash.Ptr();

    TUint32 uniqueId(0);
    uniqueId = aTableId << 28;
    uniqueId |= (ptr[3]&0x0F)<<24 | (ptr[2]<<16) | (ptr[1]<<8) | ptr[0];
    return uniqueId;
    }

// ---------------------------------------------------------------------------
// Append an item into the media array
// ---------------------------------------------------------------------------
//
EXPORT_C void MPXDbCommonUtil::AppendMediaL(
    CMPXMediaArray& aArray,
    const TDesC& aTitle,
    TMPXGeneralType aType,
    TMPXGeneralCategory aCat,
    TMPXItemId aId,
    TInt aNonPermissibleActions,
    TUint aDbflag)
    {
    MPX_FUNC("MPXDbCommonUtil::AppendMediaL");

    CMPXMedia* entry = ConstructMediaLC(aTitle, aType, aCat, aId, aNonPermissibleActions, aDbflag);
    aArray.AppendL(*entry);
    CleanupStack::PopAndDestroy(entry);
    }

// ----------------------------------------------------------------------------
// Append an item into the media array
// ----------------------------------------------------------------------------
//
EXPORT_C void MPXDbCommonUtil::PrependMediaL(
    CMPXMediaArray& aArray,
    const TDesC& aTitle,
    TMPXGeneralType aType,
    TMPXGeneralCategory aCat,
    TMPXItemId aId /* = 0 */,
    TInt aNonPermissibleActions /* = 0 */,
    TUint aDbflag /* = 0 */,
    TInt aPos /* = 0 */)
    {
    MPX_FUNC("MPXDbCommonUtil::PrependMediaL");

    CMPXMedia* entry = ConstructMediaLC(aTitle, aType, aCat, aId, aNonPermissibleActions, aDbflag);
    User::LeaveIfError(aArray.Insert(*entry, aPos));
    CleanupStack::PopAndDestroy(entry);
    }

// ----------------------------------------------------------------------------
// Append an item into the media array
// ----------------------------------------------------------------------------
//
EXPORT_C void MPXDbCommonUtil::FillInSupportedUIDsL(
    const TArray<TMPXAttribute>& aAttrs,
    RArray<TInt>& aSupportedIds)
    {
    MPX_FUNC("MPXDbCommonUtil::FillInSupportedUIDs");

    TInt attrCount(aAttrs.Count());
    for (TInt i = 0; i < attrCount; ++i)
        {
        if (aAttrs[i].ContentId() == KMPXMediaIdGeneral)
            {
            aSupportedIds.AppendL(KMPXMediaIdGeneral);
            }
        else if (aAttrs[i].ContentId() == KMPXMediaIdMusic)
            {
            aSupportedIds.AppendL(KMPXMediaIdMusic);
            }
        else if (aAttrs[i].ContentId() == KMPXMediaIdAudio)
            {
            aSupportedIds.AppendL(KMPXMediaIdAudio);
            }
        else if (aAttrs[i].ContentId() == KMPXMediaIdDrm)
            {
            aSupportedIds.AppendL(KMPXMediaIdDrm);
            }
        else if (aAttrs[i].ContentId() == KMPXMediaIdCollectionDetails)
            {
            aSupportedIds.AppendL(KMPXMediaIdCollectionDetails);
            }
        else
            {
            // ignore attribute
            }
        }
    }

// ----------------------------------------------------------------------------
// Fill in change event message with the given info
// ----------------------------------------------------------------------------
//
EXPORT_C void MPXDbCommonUtil::FillItemChangedMessageL(
    CMPXMessage& aMessage,
    TMPXItemId aId,
    TMPXChangeEventType aChangeType,
    TMPXGeneralCategory aCategory,
    TUint aUid,
    TMPXItemId aDeprecatedId)
    {
    MPX_FUNC("MPXDbCommonUtil::FillItemChangedMessageL");
    MPX_DEBUG5("MPXDbCommonUtil::FillItemChangedMessageL: type [%d], category [%d], id[0x%x], oldId[0x%x]",
               aChangeType, aCategory, aId.iId1, aDeprecatedId.iId1);

    aMessage.SetTObjectValueL<TMPXMessageId>(KMPXMessageGeneralId, KMPXMessageIdItemChanged);
    aMessage.SetTObjectValueL<TUid>(KMPXMessageCollectionId, TUid::Uid(aUid));
    aMessage.SetTObjectValueL<TMPXChangeEventType>(KMPXMessageChangeEventType, aChangeType);
    aMessage.SetTObjectValueL<TMPXGeneralCategory>(KMPXMessageMediaGeneralCategory, aCategory);
    aMessage.SetTObjectValueL<TMPXItemId>(KMPXMessageMediaGeneralId, aId);

    if ((aDeprecatedId != 0) && (aId != aDeprecatedId))
        {
        aMessage.SetTObjectValueL<TMPXItemId>(KMPXMessageMediaDeprecatedId, aDeprecatedId);
        }
    }

// ----------------------------------------------------------------------------
// Add an item changed message to the message array
// ----------------------------------------------------------------------------
//
EXPORT_C void MPXDbCommonUtil::AddItemChangedMessageL(
    CMPXMessageArray& aMessageArray,
    TMPXItemId aId,
    TMPXChangeEventType aChangeType,
    TMPXGeneralCategory aCategory,
    TUint aUid,
    TMPXItemId aDeprecatedId /* = 0 */)
    {
    MPX_FUNC("MPXDbCommonUtil::AddItemChangedMessageL");
    CMPXMessage* message = CMPXMedia::NewL();
    CleanupStack::PushL(message);

    FillItemChangedMessageL(*message, aId, aChangeType, aCategory, aUid, aDeprecatedId);
    if (FindItemChangedMessageL(aMessageArray, *message) == KErrNotFound)
        {
        aMessageArray.AppendL(*message); // ownership xfer
        }
    CleanupStack::PopAndDestroy(message);
    }

// ----------------------------------------------------------------------------
// Find the message in the array, if not KErrNotFound is returned; otherwise the
// index of the first matching message is returned
// ----------------------------------------------------------------------------
//
EXPORT_C TInt MPXDbCommonUtil::FindItemChangedMessageL(
    const CMPXMessageArray& aMessageArray,
    const CMPXMessage& aMessage)
    {
    MPX_FUNC("MPXDbCommonUtil::FindItemChangedMessageL");

    TInt index(KErrNotFound);
    TInt messageCount(aMessageArray.Count());

    for (TInt i = 0; i < messageCount; ++i)
        {
        CMPXMessage* message = aMessageArray.AtL(i);
        
        if (message->IsSupported(KMPXMessageGeneralId) &&
            message->IsSupported(KMPXMessageCollectionId) &&
            message->IsSupported(KMPXMessageChangeEventType) &&
            message->IsSupported(KMPXMessageMediaGeneralCategory) &&
            message->IsSupported(KMPXMessageMediaGeneralId) &&
            aMessage.IsSupported(KMPXMessageGeneralId) &&
            aMessage.IsSupported(KMPXMessageCollectionId) &&
            aMessage.IsSupported(KMPXMessageChangeEventType) &&
            aMessage.IsSupported(KMPXMessageMediaGeneralCategory) &&
            aMessage.IsSupported(KMPXMessageMediaGeneralId))
            {
            if (message->ValueTObjectL<TMPXMessageId>(KMPXMessageGeneralId) == aMessage.ValueTObjectL<TMPXMessageId>(KMPXMessageGeneralId) &&
                message->ValueTObjectL<TUid>(KMPXMessageCollectionId) == aMessage.ValueTObjectL<TUid>(KMPXMessageCollectionId) &&
                message->ValueTObjectL<TMPXChangeEventType>(KMPXMessageChangeEventType) == aMessage.ValueTObjectL<TMPXChangeEventType>(KMPXMessageChangeEventType) &&
                message->ValueTObjectL<TMPXGeneralCategory>(KMPXMessageMediaGeneralCategory) == aMessage.ValueTObjectL<TMPXGeneralCategory>(KMPXMessageMediaGeneralCategory) &&
                message->ValueTObjectL<TMPXItemId>(KMPXMessageMediaGeneralId) == aMessage.ValueTObjectL<TMPXItemId>(KMPXMessageMediaGeneralId))
                {
                if (!message->IsSupported(KMPXMessageMediaDeprecatedId) &&
                    !aMessage.IsSupported(KMPXMessageMediaDeprecatedId))
                    {
                    index = i;
                    break;
                    }
                else if (message->IsSupported(KMPXMessageMediaDeprecatedId) &&
                         aMessage.IsSupported(KMPXMessageMediaDeprecatedId))
                    {
                    if (message->ValueTObjectL<TMPXItemId>(KMPXMessageMediaDeprecatedId) ==
                        aMessage.ValueTObjectL<TMPXItemId>(KMPXMessageMediaDeprecatedId))
                        {
                        index = i;
                        break;
                       }
                    }
                else
                    {
                    // else do nothing
                    }
                }
            }
        }

    return index;
    }

// ----------------------------------------------------------------------------
// Get the DRM protection type of the file
// ----------------------------------------------------------------------------
//
EXPORT_C TMCDrmType MPXDbCommonUtil::GetDRMTypeL(const TDesC& aFile)
    {
    MPX_FUNC("MPXDbCommonUtil::GetDRMTypeL");

    using namespace ContentAccess;
    TInt drmProtected(0);
    TVirtualPathPtr virtualPath(aFile, KDefaultContentObject);
    CData* content = CData::NewL(virtualPath, EPeek, EContentShareReadOnly);
    CleanupStack::PushL(content);
    User::LeaveIfError(content->GetAttribute(EIsProtected, drmProtected));
    CleanupStack::PopAndDestroy( content );
    return drmProtected? EMCDrmOmaDrm : EMCDrmNone;
    }

// ----------------------------------------------------------------------------
// MPXDbUtil::ProcessSingleQuotesLC
// ----------------------------------------------------------------------------
//
EXPORT_C HBufC* MPXDbCommonUtil::ProcessSingleQuotesLC(
    const TDesC& aString)
    {
    MPX_FUNC("MPXDbCommonUtil::ProcessSingleQuotesLC");

    // reserve space for all single quotes (double the size)
    HBufC* value = HBufC::NewLC(aString.Length() * 2);
    TPtr valuePtr(value->Des());

    MPXDbCommonUtil::FindAndReplaceSingleQuote(aString, valuePtr);

    return value;
    }

// ----------------------------------------------------------------------------
// MPXDbUtil::ProcessPatternCharsLC
// 1) a percentage needs to be escaped for sqlite followed by
//    another percentage sign for escaping % for descriptor formatting, i.e.
//    % --> %% (this percentage will be treated as a percentage instead of
//    pattern matching)
// 2) since back slash is used for escaping the pattern characters, user
//    specified back slash should be escapped as well, i.e. \ --> \\
// ----------------------------------------------------------------------------
//
EXPORT_C HBufC* MPXDbCommonUtil::ProcessPatternCharsLC(
    const TDesC& aString)
    {
    MPX_FUNC("MPXDbCommonUtil::ProcessPatternCharsLC");

    // reserve space for all percentage signs (triple the size because % should
    // be replaced by %%)
    TInt srcLen(aString.Length());
    HBufC* targetString = HBufC::NewLC(aString.Length() * 3);
    TPtr targetStringPtr(targetString->Des());

    TPtrC ch;
    for (TInt i = 0; i < srcLen; ++i)
        {
        ch.Set(&aString[i], 1);
        if (ch.CompareF(KMCPercentage) == 0)
            {
            targetStringPtr.Append(KMCPercentage);
            }
           else if ( ch.CompareF( KMCBackSlash ) == 0 )
            {
            targetStringPtr.Append(KMCBackSlash);
            }
        targetStringPtr.Append(ch);            
        }

    MPX_DEBUG3("    original=%S, new=%S", &aString, targetString);
    
    return targetString;
    }

// ----------------------------------------------------------------------------
// Constructs an int SQL criterion
// ----------------------------------------------------------------------------
//
EXPORT_C HBufC* MPXDbCommonUtil::SqlCriterionLC(
    const TDesC& aCriterion,
    TInt aValue)
    {
    MPX_FUNC("MPXDbCommonUtil::SqlCriterionLC");

    HBufC* sqlCriterion = HBufC::NewLC(aCriterion.Length() + KMCIntegerLen);
    TPtr ptr = sqlCriterion->Des();
    ptr.Format(aCriterion, aValue);
    return sqlCriterion;
    }

// ----------------------------------------------------------------------------
// Constructs an int64 SQL criterion
// ----------------------------------------------------------------------------
//
EXPORT_C HBufC* MPXDbCommonUtil::SqlCriterion64LC(
    const TDesC& aCriterion,
    TInt64 aValue)
    {
    MPX_FUNC("MPXDbCommonUtil::SqlCriterion64LC");

    HBufC* sqlCriterion = HBufC::NewLC(aCriterion.Length() + KMCInt64Len);
    TPtr ptr = sqlCriterion->Des();
    ptr.Format(aCriterion, aValue);
    return sqlCriterion;
    }

// ----------------------------------------------------------------------------
// Constructs an SQL criterion using two int values
// ----------------------------------------------------------------------------
//
EXPORT_C HBufC* MPXDbCommonUtil::SqlCriterionLC(
    const TDesC& aCriterion,
    TInt aValue1,
    TInt aValue2)
    {
    MPX_FUNC("MPXDbCommonUtil::SqlCriterionLC 2");

    HBufC* sqlCriterion = HBufC::NewLC(aCriterion.Length() + 2 * KMCIntegerLen);
    TPtr ptr = sqlCriterion->Des();
    ptr.Format(aCriterion, aValue1, aValue2);
    return sqlCriterion;
    }

// ----------------------------------------------------------------------------
// Constructs an SQL criterion using two int64 values
// ----------------------------------------------------------------------------
//
EXPORT_C HBufC* MPXDbCommonUtil::SqlCriterion64LC(
    const TDesC& aCriterion,
    TInt64 aValue1,
    TInt64 aValue2)
    {
    MPX_FUNC("MPXDbCommonUtil::SqlCriterion64LC 2");

    HBufC* sqlCriterion = HBufC::NewLC(aCriterion.Length() + 2 * KMCInt64Len);
    TPtr ptr = sqlCriterion->Des();
    ptr.Format(aCriterion, aValue1, aValue2);
    return sqlCriterion;
    }

// ----------------------------------------------------------------------------
// Constructs a descriptor SQL criterion
// ----------------------------------------------------------------------------
//
EXPORT_C HBufC* MPXDbCommonUtil::SqlCriterionLC(
    const TDesC& aCriterion,
    const TDesC& aValue)
    {
    MPX_FUNC("MPXDbCommonUtil::SqlCriterionLC 3");

    HBufC* value = ProcessSingleQuotesLC(aValue);

    HBufC* sqlCriterion = HBufC::NewL(aCriterion.Length() + value->Length());
    TPtr ptr(sqlCriterion->Des());
    ptr.Format(aCriterion, value);

    CleanupStack::PopAndDestroy(value);
    CleanupStack::PushL(sqlCriterion);
    return sqlCriterion;
    }
    
// ----------------------------------------------------------------------------
// Constructs a descriptor SQL criterion
// ----------------------------------------------------------------------------
//
EXPORT_C HBufC* MPXDbCommonUtil::SqlCriterionLC(
    const TDesC& aCriterion,
    const TDesC& aValue1,
    const TDesC& aValue2)
    {
    MPX_FUNC("MPXDbCommonUtil::SqlCriterionLC 3");

    HBufC* value1 = ProcessSingleQuotesLC(aValue1);
    HBufC* value2 = ProcessSingleQuotesLC(aValue2);

    HBufC* sqlCriterion = HBufC::NewL(aCriterion.Length() + 
                                      value1->Length() + 
                                      value2->Length());
    TPtr ptr(sqlCriterion->Des());
    ptr.Format(aCriterion, value1, value2);

    CleanupStack::PopAndDestroy(value2);
    CleanupStack::PopAndDestroy(value1);
    CleanupStack::PushL(sqlCriterion);
    return sqlCriterion;
    }
    
// ----------------------------------------------------------------------------
// Constructs a descriptor SQL criterion
// ----------------------------------------------------------------------------
//
EXPORT_C HBufC* MPXDbCommonUtil::SqlCriterionLC(
    const TDesC& aCriterion,
    const TDesC& aValue1,
    TInt aValue2,
    const TDesC& aValue3,
    TInt aValue4)
    {
    MPX_FUNC("MPXDbCommonUtil::SqlCriterionLC 3");

    HBufC* value1 = ProcessSingleQuotesLC(aValue1);
    HBufC* value3 = ProcessSingleQuotesLC(aValue3);

    HBufC* sqlCriterion = HBufC::NewL(aCriterion.Length() + 
                                      value1->Length() + 
                                      value3->Length() + 
                                      2 * KMCIntegerLen);
    TPtr ptr(sqlCriterion->Des());
    ptr.Format(aCriterion, value1, aValue2, value3, aValue4);

    CleanupStack::PopAndDestroy(value3);
    CleanupStack::PopAndDestroy(value1);
    CleanupStack::PushL(sqlCriterion);
    return sqlCriterion;
    }    

// ----------------------------------------------------------------------------
// Constructs and adds an int SQL criterion to the criteria array
// ----------------------------------------------------------------------------
//
EXPORT_C TInt MPXDbCommonUtil::AddSqlCriterionL(
    CDesCArray& aSqlCriteria,
    const TDesC& aCriterion,
    TInt aValue)
    {
    MPX_FUNC("MPXDbCommonUtil::AddSqlCriterionL");

    HBufC* sqlCriterion = SqlCriterionLC(aCriterion, aValue);
    TInt length = sqlCriterion->Length();
    aSqlCriteria.AppendL(*sqlCriterion);
    CleanupStack::PopAndDestroy(sqlCriterion);
    return length;
    }

// ----------------------------------------------------------------------------
// Constructs and adds a string SQL criterion to the criteria array
// ----------------------------------------------------------------------------
//
EXPORT_C TInt MPXDbCommonUtil::AddSqlCriterionL(
    CDesCArray& aSqlCriteria,
    const TDesC& aCriterion,
    const TDesC& aValue)
    {
    MPX_FUNC("MPXDbCommonUtil::AddSqlCriterionL");

    HBufC* sqlCriterion = SqlCriterionLC(aCriterion, aValue);
    TInt length = sqlCriterion->Length();
    aSqlCriteria.AppendL(*sqlCriterion);
    CleanupStack::PopAndDestroy(sqlCriterion);
    return length;
    }


// ----------------------------------------------------------------------------
// Create a full path with input drive Id and path
// ----------------------------------------------------------------------------
//
EXPORT_C HBufC* MPXDbCommonUtil::CreateFullPathL(
    TInt aDriveId,
    const TDesC& aPath)
    {
    MPX_FUNC("MPXDbCommonUtil::CreateFullPathL");

    HBufC* hbuf = HBufC::NewLC(aPath.Length() + KMaxDriveName);
    TPtr fullPath(hbuf->Des());

    if (aDriveId != KErrNotFound)
        {
        TDriveUnit driveUnit(aDriveId);
        fullPath.Copy(driveUnit.Name());
        }

    fullPath.Append(aPath);
    CleanupStack::Pop(hbuf);
    return hbuf;
    }

// ----------------------------------------------------------------------------
// MPXDbCommonUtil::AppendValueL
// ----------------------------------------------------------------------------
//
EXPORT_C void MPXDbCommonUtil::AppendValueL(
    CDesCArray& aFields,
    CDesCArray& aValues,
    const TDesC& aField,
    const TDesC& aValue)
    {
    MPX_FUNC("MPXDbCommonUtil::AppendValueL");

    aFields.AppendL(aField);

    HBufC* value = HBufC::NewLC(aValue.Length() * 2 + 2);
    TPtr valuePtr(value->Des());

    MPXDbCommonUtil::FindAndReplaceSingleQuote(aValue, valuePtr);

    // use 'value' instead of value, 0 length strings should be ''
    //
    if( valuePtr.Length() )
        {
        valuePtr.Insert(0, KMCSingleQuote);
        valuePtr.Append(KMCSingleQuote);
        }
    else
        {
        valuePtr.Append(KMCSingleQuote);
        valuePtr.Append(KMCSingleQuote);
        }
    aValues.AppendL(valuePtr);

    CleanupStack::PopAndDestroy(value);
    }

// ----------------------------------------------------------------------------
// MPXDbCommonUtil::AppendValueL
// ----------------------------------------------------------------------------
//
EXPORT_C void MPXDbCommonUtil::AppendValueL(
    CDesCArray& aFields,
    CDesCArray& aValues,
    const TDesC& aField,
    TUint32 aValue)
    {
    MPX_FUNC("MPXDbCommonUtil::AppendValueL");

    aFields.AppendL(aField);
    TBuf<KMCIntegerLen> value;
    value.AppendNum(static_cast<TInt64>(aValue));
    aValues.AppendL(value);
    }

// ----------------------------------------------------------------------------
// Gets the MIME type for a specified URI
// ----------------------------------------------------------------------------
//
EXPORT_C TDataType MPXDbCommonUtil::GetMimeTypeForUriL(
    const TDesC& aUri)
    {
    MPX_FUNC("MPXDbUtil::GetMimeTypeForUriL");

    if ( const TDesC8 * type = FindMimeTypeFromMap (aUri) )
        {
        return TDataType(*type);
        }
    
    RApaLsSession appArc;
    User::LeaveIfError(appArc.Connect());
    CleanupClosePushL(appArc);
    TUid dummyUid(KNullUid);
    TDataType mimeType;
    appArc.AppForDocument(aUri, dummyUid, mimeType);
    CleanupStack::PopAndDestroy(&appArc);

    return mimeType;
    }

// ----------------------------------------------------------------------------
// MPXDbCommonUtil::StringFromArrayLC
// ----------------------------------------------------------------------------
//
EXPORT_C HBufC* MPXDbCommonUtil::StringFromArrayLC(
    const CDesCArray& aArray,
    const TDesC& aSeparator)
    {
    MPX_FUNC("MPXDbCommonUtil::StringFromArrayLC");

    HBufC* str(NULL);
    TInt count(aArray.Count());
    if (count)
        {
        TInt len(0);
        TInt index(0);
        for (index = 0; index < count; ++index)
            {
            len += aArray[index].Length();
            }

        str = HBufC::NewLC(len + (aSeparator.Length() * (count - 1)));
        TPtr ptr(str->Des());
        TPtrC16 item;
        for (index = 0; index < count; ++index)
            {
            item.Set(aArray[index]);
            ptr.Append(item);
            MPX_DEBUG2("aArray[index] %S", &item);
            if (index < (count - 1))
                {
                ptr.Append(aSeparator);
                }
            }
        }
    else
        {
        str = HBufC::NewLC(0);
        }

    return str;
    }

// ----------------------------------------------------------------------------
// MPXDbCommonUtil::StringFromArraysLC
// ----------------------------------------------------------------------------
//
EXPORT_C HBufC* MPXDbCommonUtil::StringFromArraysLC(
    const CDesCArray& aNameArray,
    const CDesCArray& aValueArray,
    const TDesC& aValueSeparator,
    const TDesC& aEntitySeparator)
    {
    MPX_FUNC("MPXDbCommonUtil::StringFromArraysLC");

    // calculate the length of the SET string
    TInt len(0);
    TInt index(0);
    TInt count(aNameArray.Count());
    for (index = 0; index < count; ++index)
        {
        len += aNameArray[index].Length() + aValueArray[index].Length();
        }

    // construct the result string
    HBufC* result = HBufC::NewLC(len +
        ((aValueSeparator.Length() + aEntitySeparator.Length()) * count));
    TPtr resultPtr(result->Des());
    for (index = 0; index < count; ++index)
        {
        resultPtr.Append(aNameArray[index]);
        resultPtr.Append(aValueSeparator);
        resultPtr.Append(aValueArray[index]);

        if (index < count - 1)
            {
            resultPtr.Append(aEntitySeparator);
            }
        }

    return result;
    }

// ----------------------------------------------------------------------------
// MPXDbCommonUtil::TTimeToDesLC
// Converts a TTime to the internal SQLite format (YYYY-MM-DD HH:MM:SS).
// ----------------------------------------------------------------------------
//
EXPORT_C HBufC* MPXDbCommonUtil::TTimeToDesLC(
    const TTime& aTime)
    {
    MPX_FUNC("MPXDbCommonUtil::TTimeToDesLC");

    HBufC* dateTime;
    if (aTime == Time::NullTTime())
        {
        dateTime = HBufC::NewLC(0);
        }
    else
        {
        _LIT(KDateTimeFormat, "%04d-%02d-%02d %02d:%02d:%02d");
        
        TTime time(0);

        // negative time means BC, but format string will be invalid with our format,
        // i.e. %04d in KDateTimeFormat when year is -1 will result in "00-1" and
        // the whole string becomes "00-1-01-01 00:00:00" which will result in error,
        // so set to 0 in such cases
        TDateTime dt = aTime>time ? aTime.DateTime() : time.DateTime();
        TInt dateTimeLen = KDateTimeFormat().Length();
        dateTime = HBufC::NewLC(dateTimeLen);
        TPtr dateTimePtr = dateTime->Des();
        dateTimePtr.Format(KDateTimeFormat,
                        dt.Year(),
                        dt.Month() + 1, // zero based
                        dt.Day() + 1,   // zero based
                        dt.Hour(),
                        dt.Minute(),
                        dt.Second());
        }
    return dateTime;
    }

// ----------------------------------------------------------------------------
// MPXDbCommonUtil::DesToTTimeL
// Converts a date time string in the internal SQLite format (YYYY-MM-DD HH:MM:SS)
// to a TTime. TTime can only parse in the DD-MM-YYYY HH:MM:SS format.
// ----------------------------------------------------------------------------
//
EXPORT_C TTime MPXDbCommonUtil::DesToTTimeL(
    const TDesC& aDateTime)
    {
    MPX_FUNC("MPXDbCommonUtil::DesToTTimeL");

    TTime time(0);
    if (aDateTime.Length() != 0)
        {
        _LIT(KDash, "-");
        _LIT(KSpace, " ");

        TLocale locale;
        TDateFormat iDateFormat = locale.DateFormat();

        HBufC* dateTime = HBufC::NewLC(aDateTime.Length());
        TPtr dateTimePtr = dateTime->Des();

        //as TTime::Parse is locale dependent, check it:
        if(iDateFormat==EDateEuropean)
            {
            dateTimePtr.Append(aDateTime.Mid(8, 2));//day DD
            dateTimePtr.Append(KDash);
            dateTimePtr.Append(aDateTime.Mid(5, 2));//month MM
            dateTimePtr.Append(KDash);
            dateTimePtr.Append(aDateTime.Left(4));//year YYYY
            dateTimePtr.Append(KSpace);
            }
        else if(iDateFormat==EDateJapanese)
            {
            dateTimePtr.Append(aDateTime.Left(4));//year YYYY
            dateTimePtr.Append(KDash);
            dateTimePtr.Append(aDateTime.Mid(5, 2));//month MM
            dateTimePtr.Append(KDash);
            dateTimePtr.Append(aDateTime.Mid(8, 2));//day DD
            dateTimePtr.Append(KSpace);
            }
        else //iDateFormat==EDateAmerican
            {
            dateTimePtr.Append(aDateTime.Mid(5, 2));//month MM
            dateTimePtr.Append(KDash);
            dateTimePtr.Append(aDateTime.Mid(8, 2));//day DD
            dateTimePtr.Append(KDash);
            dateTimePtr.Append(aDateTime.Left(4));//year YYYY
            dateTimePtr.Append(KSpace);            
            }

		    // When colon (:) is set as Date separator in Date and Time setting, 
		    // colon in Time descriptors is parsed as Date separator. 
        if ( locale.DateSeparator(1) == ':')
            {
            _LIT(KDot, ".");
        
        		// time HH.MM.SS
            dateTimePtr.Append( aDateTime.Mid(11, 2) );
            dateTimePtr.Append( KDot );
            dateTimePtr.Append( aDateTime.Mid(14, 2) );
            dateTimePtr.Append( KDot );
            dateTimePtr.Append( aDateTime.Mid(17, 2) );
            }
        else
            {
            dateTimePtr.Append(aDateTime.Right(8));//time HH:MM:SS
            }

        User::LeaveIfError(time.Parse(dateTimePtr));
        CleanupStack::PopAndDestroy(dateTime);
        }
    else
        {
        time = Time::NullTTime();
        }
    return time;
    }

// ----------------------------------------------------------------------------
// MPXDbCommonUtil::CurrentTimeDesLC
// ----------------------------------------------------------------------------
//
EXPORT_C HBufC* MPXDbCommonUtil::CurrentTimeDesLC()
    {
    MPX_FUNC("MPXDbCommonUtil::CurrentTimeDesLC");

    TTime time;
    time.HomeTime();

    return TTimeToDesLC(time);
    }

// ----------------------------------------------------------------------------
// MPXDbCommonUtil::CurrentDateDesLC
// ----------------------------------------------------------------------------
//
EXPORT_C HBufC* MPXDbCommonUtil::CurrentDateDesLC()
    {
    MPX_FUNC("MPXDbCommonUtil::CurrentDateDesLC");

    TTime time;
    time.HomeTime();

    // Round off to the nearest hour
    TDateTime date(time.DateTime());
    date.SetMinute(0);
    date.SetSecond(0);
    date.SetMicroSecond(0);

    return TTimeToDesLC(TTime(date));
    }

// ----------------------------------------------------------------------------
// MPXDbCommonUtil::GetDriveL
// ----------------------------------------------------------------------------
//
EXPORT_C TInt MPXDbCommonUtil::GetDriveL(
    const TDesC& aUri,
    TDriveUnit& aDrive)
    {
    MPX_FUNC("MPXDbCommonUtil::GetDriveL");

    TInt err(KErrNotFound);
    TParsePtrC parser(aUri);
    if (parser.Drive().Length())
        {
        aDrive = TDriveUnit(aUri);
        err = KErrNone;
        }

    return err;
    }

// ----------------------------------------------------------------------------
// MPXDbCommonUtil::AttributeExistsL
// ----------------------------------------------------------------------------
//
EXPORT_C TBool MPXDbCommonUtil::AttributeExists(
    const TArray<TMPXAttribute>& aAttrs,
    const TMPXAttribute& aAttribute)
    {
    MPX_FUNC("MPXDbCommonUtil::AttributeExists");

    TBool ret(EFalse);

    TUint content(aAttribute.ContentId());
    TUint attribute(aAttribute.AttributeId());

    TInt count(aAttrs.Count());
    for (TInt i = 0; i < count; ++i)
        {
        if ((aAttrs[i].ContentId() == content) &&
            (aAttrs[i].AttributeId() & attribute))
            {
            ret = ETrue;
            break;
            }
        }

    return ret;
    }

// ----------------------------------------------------------------------------
// MPXDbCommonUtil::ConstructMediaLC
// ----------------------------------------------------------------------------
//
CMPXMedia* MPXDbCommonUtil::ConstructMediaLC(
    const TDesC& aTitle,
    TMPXGeneralType aType,
    TMPXGeneralCategory aCat,
    TMPXItemId aId,
    TInt aNonPermissibleActions,
    TUint aDbflag)
    {
    MPX_FUNC("MPXDbCommonUtil::ConstructMediaLC");

    RArray<TInt> supportedIds;
    CleanupClosePushL(supportedIds);
    supportedIds.AppendL(KMPXMediaIdGeneral);
    CMPXMedia* entry = CMPXMedia::NewL(supportedIds.Array());
    CleanupStack::PopAndDestroy(&supportedIds);
    CleanupStack::PushL(entry);
    entry->SetTextValueL(KMPXMediaGeneralTitle, aTitle);
    entry->SetTObjectValueL<TMPXGeneralType>(KMPXMediaGeneralType, aType);
    entry->SetTObjectValueL<TMPXGeneralCategory>(KMPXMediaGeneralCategory, aCat);
    entry->SetTObjectValueL<TMPXItemId>(KMPXMediaGeneralId, aId);
    entry->SetTObjectValueL<TUint>(KMPXMediaGeneralFlags, aDbflag);

    if (aNonPermissibleActions)
        {
        // set non-permissible actions
        entry->SetTObjectValueL<TMPXGeneralNonPermissibleActions>(KMPXMediaGeneralNonPermissibleActions,
            static_cast<TMPXGeneralNonPermissibleActions>(aNonPermissibleActions));
        }

    return entry;
    }

// ----------------------------------------------------------------------------
// MPXDbCommonUtil::GetColumnTextL
// ----------------------------------------------------------------------------
//
EXPORT_C TPtrC MPXDbCommonUtil::GetColumnTextL(
	RSqlStatement& aStatement, 
	TInt aField)
	{
    MPX_FUNC("MPXDbCommonUtil::GetColumnTextL");
    
    TPtrC text;
	if (aStatement.ColumnSize(aField))
		{
	    text.Set(aStatement.ColumnTextL(aField));
		}
	else
		{
	    text.Set(KNullDesC);    	        		
		}	

    return text;
	}

// ----------------------------------------------------------------------------
// Add an album item changed message to the message array
// ----------------------------------------------------------------------------
//
EXPORT_C void MPXDbCommonUtil::AddItemAlbumChangedMessageL(
    CMPXMessageArray& aMessageArray,
    TMPXItemId aId,
    TMPXChangeEventType aChangeType,
    TMPXGeneralCategory aCategory,
    TUint aUid,
    TBool aAlbumArt,
    TMPXItemId aDeprecatedId)
    {
    MPX_FUNC("MPXDbCommonUtil::AddItemChangedMessageL");
    CMPXMessage* message = CMPXMedia::NewL();
    CleanupStack::PushL(message);

    FillItemChangedMessageL(*message, aId, aChangeType, aCategory, aUid,
    		aDeprecatedId );
    if ( aAlbumArt )
        {
        message->SetTObjectValueL<TMPXItemId>(KMPXMessageMediaDeprecatedId, aId);
        }
    if (FindItemChangedMessageL(aMessageArray, *message) == KErrNotFound)
        {
        aMessageArray.AppendL(*message); // ownership xfer
        }
    CleanupStack::PopAndDestroy(message);
    }
// End of File
