/*
* 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:  Responsible for interation with the category tables:
*                Artist, Album, Genre, Composer and AbstractAlbum
*
*
*/


// INCLUDE FILES
#include <mpxlog.h>
#include <bautils.h>
#include <mpxmediamusicdefs.h>
#include "mpxdbabstractalbum.h"
#include "mpxdbpluginqueries.h"
#include "mpxdbmanager.h"
#include "mpxdbcommonutil.h"
#include "mpxcollectiondbstd.h"
#include "mpxdbcommondef.h"
#include "mpxcollectiondbdef.h"

#ifdef RD_MPX_TNM_INTEGRATION
_LIT( KImageFileType, "image/jpeg" );
#endif //RD_MPX_TNM_INTEGRATION


// CONSTANTS

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

// ----------------------------------------------------------------------------
// Two-phased constructor.
// ----------------------------------------------------------------------------
//
CMPXDbAbstractAlbum* CMPXDbAbstractAlbum::NewL(
    CMPXDbManager& aDbManager,
    TMPXGeneralCategory aCategory, RFs& aFs)
    {
    MPX_FUNC("CMPXDbAbstractAlbum::NewL");

    CMPXDbAbstractAlbum* self = CMPXDbAbstractAlbum::NewLC(aDbManager, aCategory, aFs);
    CleanupStack::Pop(self);
    return self;
    }

// ----------------------------------------------------------------------------
// Two-phased constructor.
// ----------------------------------------------------------------------------
//
CMPXDbAbstractAlbum* CMPXDbAbstractAlbum::NewLC(
    CMPXDbManager& aDbManager,
    TMPXGeneralCategory aCategory, RFs& aFs)
    {
    MPX_FUNC("CMPXDbAbstractAlbum::NewLC");

    CMPXDbAbstractAlbum* self = new (ELeave) CMPXDbAbstractAlbum(aDbManager, aCategory, aFs);
    CleanupStack::PushL(self);
    self->ConstructL();
    return self;
    }

// ----------------------------------------------------------------------------
// Destructor
// ----------------------------------------------------------------------------
//
CMPXDbAbstractAlbum::~CMPXDbAbstractAlbum()
    {
    MPX_FUNC("CMPXDbAbstractAlbum::~CMPXDbAbstractAlbum");
#ifdef RD_MPX_TNM_INTEGRATION
    delete iTNManager;
#endif //RD_MPX_TNM_INTEGRATION
    }

// ----------------------------------------------------------------------------
// CMPXDbAbstractAlbum::GetDriveIdL
// ----------------------------------------------------------------------------
//
TInt CMPXDbAbstractAlbum::GetDriveIdL(
    TUint32 aAbstractAlbumId)
    {
    MPX_FUNC("CMPXDbAbstractAlbum::GetDriveIdL");
    return MPXDbCommonUtil::GetDriveIdMatchVolIdL(iDbManager.Fs(),
        ExecuteIntQueryL(KCriterionCategoryVolumeId, aAbstractAlbumId));
    }


// ----------------------------------------------------------------------------
// CMPXDbAbstractAlbum::AddItemL
// ----------------------------------------------------------------------------
//
TUint32 CMPXDbAbstractAlbum::AddItemL(
    const TDesC& aUri,
    const TDesC& aName,
    const TDesC& aAlbumArtist,
    TInt aDriveId,
    TBool& aNewRecord,
    TBool aCaseSensitive)
    {
    MPX_FUNC("CMPXDbAbstractAlbum::AddItemL");

    TUint32 rowId(MPXDbCommonUtil::GenerateUniqueIdL(iDbManager.Fs(), EMPXAbstractAlbum,
        aUri, aCaseSensitive));
    aNewRecord = !CategoryItemExistsL(aDriveId, rowId);

    if ( aNewRecord )
        {
        HBufC* uri = MPXDbCommonUtil::ProcessSingleQuotesLC(aUri);
        HBufC* name = MPXDbCommonUtil::ProcessSingleQuotesLC(aName);
        HBufC* albumartist = MPXDbCommonUtil::ProcessSingleQuotesLC(aAlbumArtist);

        iDbManager.ExecuteQueryL(aDriveId, KQueryAbstractAlbumInsert, rowId, uri, name, albumartist, 0, MPXDbCommonUtil::GetVolIdMatchDriveIdL(iDbManager.Fs(), aDriveId));
        CleanupStack::PopAndDestroy(3, uri);
        }
    else
        {
        MPX_DEBUG1("CMPXDbAbstractAlbum::AddItemL, increase song count for abstractalbum");
        // increment the number of songs for the category
        HBufC* query = PreProcessStringLC(KQueryCategoryIncrementSongCount);
        iDbManager.ExecuteQueryL(aDriveId, *query, rowId);
        CleanupStack::PopAndDestroy(query);
        }

    return rowId;
    }

// ----------------------------------------------------------------------------
// CMPXDbAbstractAlbum::AddUpdatedItemL
// ----------------------------------------------------------------------------
//
TUint32 CMPXDbAbstractAlbum::AddUpdatedItemL(TUint32 aOldId, const TDesC& newUri)
    {
    MPX_FUNC("CMPXDbAbstractAlbum::AddUpdatedItemL");
    iRenameTN = ETrue;
    
    //get the existing item based on aOldId
    HBufC* query = NULL;
    query = PreProcessStringLC(KQueryCategoryItem);
    RSqlStatement recordset(iDbManager.ExecuteSelectQueryL(*query, aOldId));
    CleanupStack::PopAndDestroy(query);
    
    CleanupClosePushL(recordset);
    TBool newRecord(ETrue);
    if (recordset.Next() != KSqlAtRow)
        {
        User::Leave(KErrNotFound);
        }
    //save the existing entry fields values for renaming purpose
    const TDesC& name(MPXDbCommonUtil::GetColumnTextL (recordset, EAbstractAlbumName));
    const TDesC& albumartist(MPXDbCommonUtil::GetColumnTextL (recordset, EAbstractAlbumArtist));

    TUint32 itemId = AddItemL(newUri, name, albumartist, GetDriveIdL(aOldId), newRecord, EFalse);
    CleanupStack::PopAndDestroy(&recordset);

    return itemId;
    }

// ----------------------------------------------------------------------------
// CMPXDbAbstractAlbum::DecrementSongsForCategoryL
// ----------------------------------------------------------------------------
//
void CMPXDbAbstractAlbum::DecrementSongsForCategoryL(
    const TUint32 aId,
    TInt aDriveId,
    CMPXMessageArray* aItemChangedMessages,
    TBool& aItemExist,
    TBool aMtpInUse)
    {
    MPX_FUNC("CMPXDbAbstractAlbum::DecrementSongsForCategoryL");
    
    TInt songCount = GetSongsCountL(aDriveId, aId);
    //while MTP connection, just decrease songCount in DB, do not do deletion.
    if ( songCount > 0 )
        {
        aItemExist = ETrue;
        // decrement the number of songs for the category
        HBufC* query = PreProcessStringLC(KQueryCategoryDecrementSongCount);
        iDbManager.ExecuteQueryL(aDriveId, *query, aId);
        CleanupStack::PopAndDestroy(query);
        songCount--;
        }
    if (songCount == 0)
        {
        //get uri
        HBufC* uri = GetUriL(aId);
        CleanupStack::PushL(uri);
            
        if (!aMtpInUse)
	        {       
	        DeleteAbstractAlbumEntryL(aId, aDriveId);
	        MPX_DEBUG1("CMPXDbAbstractAlbum::DecrementSongsForCategoryL,implicitly delete AbstractAlbum Object when it has 0 references");
	        aItemExist = EFalse;
	        if (aItemChangedMessages)
	            {
	            // add the item changed message
	            MPXDbCommonUtil::AddItemChangedMessageL(*aItemChangedMessages, aId, EMPXItemDeleted,
	                EMPXAbstractAlbum, KDBPluginUid);
	            }
	        //delete .alb file from file system                
	        TInt err = BaflUtils::DeleteFile(iFs, *uri);                       
	        if(KErrNone != err)
	            {
	            MPX_DEBUG2("CMPXDbAbstractAlbum::DecrementSongsForCategoryL,File not deleted from file system with err=%d", err);
	            }   
	        }
        if(!iRenameTN)
	        {
	        HandleTNL(*uri);
	        }   
        CleanupStack::PopAndDestroy(uri);
        }  
    }

// ----------------------------------------------------------------------------
// CMPXDbAbstractAlbum::RemoveAbstractAlbumL
// ----------------------------------------------------------------------------
//
void CMPXDbAbstractAlbum::RemoveAbstractAlbumL(TUint32 aAbstractAlbumId, 
    CMPXMessageArray& aItemChangedMessages, TBool aFileDeleted)
    {
    MPX_FUNC("CMPXDbAbstractAlbum::RemoveAbstractAlbumL");
    HBufC* uri = GetUriL(aAbstractAlbumId);
    CleanupStack::PushL(uri);
    
    DeleteAbstractAlbumEntryL(aAbstractAlbumId);
    HandleTNL(*uri);
    if (!aFileDeleted)
        {             
        TInt err = BaflUtils::DeleteFile(iFs, *uri);                       
        if(KErrNone != err)
            {
            MPX_DEBUG2("CMPXDbAbstractAlbum::RemoveAbstractAlbumL,File not deleted from file system with err=%d", err);
            }   
        }   
    MPXDbCommonUtil::AddItemChangedMessageL(aItemChangedMessages, aAbstractAlbumId, EMPXItemDeleted, EMPXAbstractAlbum, KDBPluginUid);            
    CleanupStack::PopAndDestroy(uri);
    }


// ----------------------------------------------------------------------------
// CMPXDbAbstractAlbum::HandleTNL
// ----------------------------------------------------------------------------
//
void CMPXDbAbstractAlbum::HandleTNL( const TDesC& aOldPath,
        const TDesC& aNewPath, TInt aPriority )
  {
  MPX_FUNC("CMPXDbAbstractAlbum::HandleTNL");

  if (aNewPath.Compare(KNullDesC)==0 && aOldPath.Compare(KNullDesC)!=0)
      {         
      // remove from thumbnail database table
      MPX_DEBUG1("CMPXDbAbstractAlbum::HandleTNL, delete TN");  
      CThumbnailObjectSource* source = CThumbnailObjectSource::NewLC(
               aOldPath, KImageFileType );
      iTNManager->DeleteThumbnails( *source );
      CleanupStack::PopAndDestroy( source );
      }
   else if (aNewPath.Compare(KNullDesC)!=0)
      {
      //rename thumbnail
      MPX_DEBUG1("CMPXDbAbstractAlbum::HandleTNL, rename TN");
      iTNManager->RenameThumbnailsL( aOldPath,  aNewPath, aPriority );
      //after rename, reset flag
      iRenameTN = EFalse;
      }
 }


// ----------------------------------------------------------------------------
// CMPXDbAbstractAlbum::UpdateItemL
// ----------------------------------------------------------------------------
//
void CMPXDbAbstractAlbum::UpdateItemL(
    TUint32 aId,
    const CMPXMedia& aMedia,
    TInt aDriveId,
    CMPXMessageArray* aItemChangedMessages)
    {
    MPX_FUNC("CMPXDbAbstractAlbum::UpdateItemL");

    CDesCArrayFlat* fields = new (ELeave) CDesCArrayFlat(EAbstractAlbumFieldCount);
    CleanupStack::PushL(fields);
    CDesCArrayFlat* values = new (ELeave) CDesCArrayFlat(EAbstractAlbumFieldCount);
    CleanupStack::PushL(values);

    // process the media parameter and construct the fields and values array
    GenerateAbstractAlbumFieldsValuesL(aMedia, *fields, *values);

    // construct the SET string
    HBufC* setStr = MPXDbCommonUtil::StringFromArraysLC(*fields, *values, KMCEqualSign, KMCCommaSign);

    if (setStr->Length())
        {
        // execute the query
        iDbManager.ExecuteQueryL(aDriveId, KQueryAbstractAlbumUpdate, setStr, aId);
        MPXDbCommonUtil::AddItemAlbumChangedMessageL(*aItemChangedMessages, aId, EMPXItemModified,
                EMPXAbstractAlbum, KDBPluginUid, ETrue, 0 );
        }
    CleanupStack::PopAndDestroy(setStr);
    CleanupStack::PopAndDestroy(values);
    CleanupStack::PopAndDestroy(fields);
    }


// ----------------------------------------------------------------------------
// CMPXDbAbstractAlbum::GetUriL
// ----------------------------------------------------------------------------
//
HBufC* CMPXDbAbstractAlbum::GetUriL(
    TUint32 aId)
    {
    MPX_FUNC("CMPXDbAbstractAlbum::GetUriL");

    RSqlStatement recordset(GetCategoryRecordL(aId));
    CleanupClosePushL(recordset);
    HBufC* uri = NULL;
    if (recordset.Next() == KSqlAtRow)
        {
        uri = MPXDbCommonUtil::GetColumnTextL(recordset, EAbstractAlbumUri).AllocL();     
        }
    else
        {
        //entry is deleted due to garbage collection 
        MPX_DEBUG1("CMPXDbAbstractAlbum::GetUriL, no uri, entry is deleted due to garbage collection"); 
        TPtrC nullUri(KNullDesC);
        uri = nullUri.AllocL();
        }
    CleanupStack::PopAndDestroy(&recordset);    
    return uri;
    }


// ----------------------------------------------------------------------------
// CMPXDbAbstractAlbum::UpdateMediaL
// ----------------------------------------------------------------------------
//
void CMPXDbAbstractAlbum::UpdateMediaL(
    RSqlStatement& aRecord,
    const TArray<TMPXAttribute>& aAttrs,
    CMPXMedia& aMedia)
    {
    MPX_FUNC("CMPXDbAbstractAlbum::UpdateMediaL");

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

           if (contentId == KMPXMediaIdGeneral)
               {
               if (attributeId & EMPXMediaGeneralId)
                   {
                   MPX_DEBUG1("    EMPXMediaGeneralId");
                   aMedia.SetTObjectValueL<TMPXItemId>(KMPXMediaGeneralId,
                       aRecord.ColumnInt64(EAbstractAlbumUniqueId));
                   }
               if (attributeId & EMPXMediaGeneralTitle)
                   {
                   MPX_DEBUG1("    EMPXMediaGeneralTitle");
                   TPtrC title(MPXDbCommonUtil::GetColumnTextL(aRecord, EAbstractAlbumName));
                   aMedia.SetTextValueL(KMPXMediaGeneralTitle, title);
                   MPX_DEBUG2("    AbstractAlbumName[%S]", &title);
                   }
               if (attributeId & EMPXMediaGeneralCount)
                   {
                   MPX_DEBUG1("    EMPXMediaGeneralCount");
                   TInt songCount = GetSongsCountL(KDbManagerAllDrives,
                                aRecord.ColumnInt64(EAbstractAlbumUniqueId));
                   aMedia.SetTObjectValueL<TInt>(KMPXMediaGeneralCount, songCount );
                   }
               if (attributeId & EMPXMediaGeneralDrive ||
                    (attributeId & EMPXMediaGeneralUri))
                   {                       
                   TUint32 volId(aRecord.ColumnInt64(EAbstractAlbumVolumeId));
                   TInt driveId = MPXDbCommonUtil::GetDriveIdMatchVolIdL(iDbManager.Fs(), volId);
                   MPX_DEBUG3("volId = %d, driveId = %d", volId, driveId);

                   // handle possibly delay from framework notification
                   if (driveId < 0)
                       {
                       MPX_DEBUG1("invalid driveId, leave with KErrNotReady");
                       User::Leave(KErrNotReady);
                       }
                   TDriveUnit driveUnit(driveId);
                   if (attributeId & EMPXMediaGeneralUri)
                       {                              
                       TPtrC uri(MPXDbCommonUtil::GetColumnTextL(aRecord, EAbstractAlbumUri));
                       aMedia.SetTextValueL(KMPXMediaGeneralUri, uri);
                       MPX_DEBUG2("    AbstractAlbum URI[%S]", &uri);
                       }
                  if (attributeId & EMPXMediaGeneralDrive)
                       {
                       aMedia.SetTextValueL(KMPXMediaGeneralDrive, driveUnit.Name());
                       }
                   }
               } // end if contentId == KMPXMediaIdGeneral

           else if ( contentId == KMPXMediaIdMusic)
               {
               if (attributeId & EMPXMediaMusicAlbumArtist)
                   {
                   MPX_DEBUG1("    EMPXMediaMusicAlbumArtist");
                   TPtrC albumartist(MPXDbCommonUtil::GetColumnTextL(aRecord, EAbstractAlbumArtist));
                   aMedia.SetTextValueL(KMPXMediaMusicAlbumArtist, albumartist);
                   MPX_DEBUG2("    albumartist[%S]", &albumartist);
                   }
               }

           } // end for
       aMedia.SetTObjectValueL<TMPXGeneralType>(KMPXMediaGeneralType, EMPXItem);
       aMedia.SetTObjectValueL<TMPXGeneralCategory>(KMPXMediaGeneralCategory, EMPXAbstractAlbum);
    }

// ----------------------------------------------------------------------------
// CMPXDbAbstractAlbum::GetAllItemsWithNoSongL
// ----------------------------------------------------------------------------
//
void CMPXDbAbstractAlbum::GetAllItemsWithNoSongL(RArray<TUint32>& aItemsIds)
    {
    MPX_FUNC("CMPXDbAbstractAlbum::GetAllItemsWithNoSongL");
    RSqlStatement recordset(iDbManager.ExecuteSelectQueryL(KQueryAbstractAlbumsWithNoSong));
    CleanupClosePushL(recordset);

    TInt err(KErrNone);
    while ((err = recordset.Next()) == KSqlAtRow)
        {
        TUint32 uniqueID(recordset.ColumnInt64(EAbstractAlbumUniqueId));
        aItemsIds.AppendL(uniqueID);
        }
    CleanupStack::PopAndDestroy(&recordset);
    if (err!= KSqlAtEnd)
        {
        User::Leave(KErrCorrupt);
        } 	
    }


// ----------------------------------------------------------------------------
// CMPXDbAbstractAlbum::GenerateAbstractAlbumFieldsValuesL
// ----------------------------------------------------------------------------
//
void CMPXDbAbstractAlbum::GenerateAbstractAlbumFieldsValuesL(const CMPXMedia& aMedia, CDesCArray& aFields, CDesCArray& aValues)
    {
    MPX_FUNC("CMPXDbAbstractAlbum::GenerateAbstractAlbumFieldsValuesL");
    //support Winlogo use case
    if (aMedia.IsSupported(KMPXMediaGeneralTitle))
        {
        TPtrC truncatedName(aMedia.ValueText(KMPXMediaGeneralTitle).Left(KMCMaxTextLen));
        MPXDbCommonUtil::AppendValueL(aFields, aValues, KMCCategoryName, truncatedName);
        }
    //support Winlogo use case
    if (aMedia.IsSupported(KMPXMediaMusicAlbumArtist))
        {
        TPtrC truncatedAlbumArtist(aMedia.ValueText(KMPXMediaMusicAlbumArtist).Left(KMCMaxTextLen));
        MPXDbCommonUtil::AppendValueL(aFields, aValues, KMCMusicAlbumArtist, truncatedAlbumArtist);
        }
     }

// ----------------------------------------------------------------------------
// CMPXDbAbstractAlbum::DeleteAbstractAlbumEntryL
// ----------------------------------------------------------------------------
//
void CMPXDbAbstractAlbum::DeleteAbstractAlbumEntryL(
    TUint32 aAbstractAlbumId, TInt aDriveId)
    {
    MPX_FUNC("CMPXDbAbstractAlbum::DeleteAbstractAlbumEntryL");

    //delete entry from table        
    if (aDriveId)
        DeleteCategoryL(aAbstractAlbumId, aDriveId);
    else
        {
        TInt drive = MPXDbCommonUtil::GetDriveIdMatchVolIdL(iDbManager.Fs(),
        ExecuteIntQueryL(KCriterionCategoryVolumeId, aAbstractAlbumId));
        DeleteCategoryL(aAbstractAlbumId, drive);
        }
    }

// ----------------------------------------------------------------------------
// CMPXDbAlbum::CreateTableL
// ----------------------------------------------------------------------------
//
void CMPXDbAbstractAlbum::CreateTableL(
    RSqlDatabase& aDatabase,
    TBool /* aCorruptTable */)
    {
    MPX_FUNC("CMPXDbAbstractAlbum::CreateTableL");

    // create the table
    HBufC* query = PreProcessStringLC(KAbstractAlbumCreateTable);
    User::LeaveIfError(aDatabase.Exec(*query));
    CleanupStack::PopAndDestroy(query);

    // do not create an index on the Name field
    // as it only slows down the insert/update queries overall
    }

// ----------------------------------------------------------------------------
// CMPXDbAlbum::CheckTableL
// ----------------------------------------------------------------------------
//
TBool CMPXDbAbstractAlbum::CheckTableL(
    RSqlDatabase& aDatabase)
    {
    MPX_FUNC("CMPXDbAbstractAlbum::CheckTableL");

    HBufC* query = PreProcessStringLC(KAbstractAlbumCheckTable);
    TBool check(DoCheckTable(aDatabase, *query));
    CleanupStack::PopAndDestroy(query);

    return check;
    }


// ----------------------------------------------------------------------------
// Constructor
// ----------------------------------------------------------------------------
//
CMPXDbAbstractAlbum::CMPXDbAbstractAlbum(
    CMPXDbManager& aDbManager,
    TMPXGeneralCategory aCategory, RFs& aFs) :
    CMPXDbCategory(aDbManager, aCategory),
    iFs(aFs)
    {
    MPX_FUNC("CMPXDbAbstractAlbum::CMPXDbAbstractAlbum");
    }

// ----------------------------------------------------------------------------
// Second phase constructor.
// ----------------------------------------------------------------------------
//
void CMPXDbAbstractAlbum::ConstructL()
    {
    MPX_FUNC("CMPXDbAbstractAlbum::ConstructL");

    BaseConstructL();
#ifdef RD_MPX_TNM_INTEGRATION
    // Create Thumbnail Manager instance. This object is the observer.
    iTNManager = CThumbnailManager::NewL( *this );
    iRenameTN = EFalse;
#endif //RD_MPX_TNM_INTEGRATION
    }



// ---------------------------------------------------------------------------
// CMPXDbAbstractAlbum::ThumbnailReady
// Callback but not used here
// ---------------------------------------------------------------------------
void CMPXDbAbstractAlbum::ThumbnailPreviewReady(
        MThumbnailData& /*aThumbnail*/, TThumbnailRequestId /*aId*/ )
    {
    }


// ---------------------------------------------------------------------------
// CMPXDbAbstractAlbum::ThumbnailReady
// Callback but not used here
// ---------------------------------------------------------------------------
void CMPXDbAbstractAlbum::ThumbnailReady( TInt /*aError*/,
        MThumbnailData& /*aThumbnail*/, TThumbnailRequestId /*aId*/ )
    {
    }
// End of File
