/// @todo minor: Rowland Cook 12/06/2007 Add method decription.
// -----------------------------------------------------------------------------
// TGlxCommandFactory::AddToContainerCommandLC
// -----------------------------------------------------------------------------
//	
EXPORT_C CMPXCommand* TGlxCommandFactory::AddToContainerCommandLC(
        const TDesC& aUri, 
        const CMPXCollectionPath& aTargetContainers)
    {
    
    CMPXCommand* command = CMPXCommand::NewL();
    CleanupStack::PushL(command);
    
    // Set command id
    command->SetTObjectValueL<TInt>(KMPXCommandGeneralId, KGlxCommandIdAdd);  
    
    // Set URI
    command->SetTextValueL(KMPXCommandGeneralSourceUri, aUri); 
    
    // Add path of selected items
    command->SetCObjectValueL<CMPXCollectionPath>(KMPXMediaGeneralContainerId, &const_cast<CMPXCollectionPath&>(aTargetContainers));    

    // Add collection plugin id to command object
/// @todo minor: Add comment as to the meaning of the value zero in Comparison and aTargetContainers.Id(0)
    if (aTargetContainers.Levels() > 0) 
        {
        command->SetTObjectValueL<TUid>(KMPXCommandGeneralCollectionId, TUid::Uid(aTargetContainers.Id(0)));        
        }
    
    return command;      
    }
/// @todo minor: Rowland Cook 12/06/2007 Add method decription.
// -----------------------------------------------------------------------------
// TGlxCommandFactory::SetDescriptionCommandLC
// -----------------------------------------------------------------------------
//	
EXPORT_C CMPXCommand* TGlxCommandFactory::SetDescriptionCommandLC(const TDesC& aDescription, 
        const CMPXCollectionPath& aSourcePath) 
    {
    CMPXCommand* command = BasicCommandLC(KGlxCommandIdSet, aSourcePath);
    
    // Set description
    command->SetTextValueL(KMPXMediaGeneralComment, aDescription);    
    
    return command;
    }
/// @todo minor: Rowland Cook 12/06/2007 Add method decription.
// -----------------------------------------------------------------------------
// TGlxCommandFactory::RenameCommandLC
// -----------------------------------------------------------------------------
//	
EXPORT_C CMPXCommand* TGlxCommandFactory::RenameCommandLC(const TDesC& aNewTitle, 
    const CMPXCollectionPath& aSourcePath)
    {
    CMPXCommand* command = BasicCommandLC(KGlxCommandIdSet, aSourcePath);
    
    // Set title
    command->SetTextValueL(KMPXMediaGeneralTitle, aNewTitle);    
   
    return command;
    }
/// @todo minor: Rowland Cook 12/06/2007 Add method decription.
// -----------------------------------------------------------------------------
// TGlxCommandFactory::CopyCommandLC
// -----------------------------------------------------------------------------
//	
EXPORT_C CMPXCommand* TGlxCommandFactory::CopyCommandLC(const TDesC& aTargetDrive, 
    const CMPXCollectionPath& aSourcePath)
    {
    CMPXCommand* command = BasicCommandLC(KGlxCommandIdAdd, aSourcePath);
    
    // Set target drive
    command->SetTextValueL(KMPXMediaGeneralDrive, aTargetDrive);    
    
    return command;
    }
/// @todo minor: Rowland Cook 12/06/2007 Add method decription.
// -----------------------------------------------------------------------------
// TGlxCommandParser::ValueL
// -----------------------------------------------------------------------------
//	
template<typename T> T TGlxCommandParser::ValueL(const TMPXAttribute & aAttribute, const CMPXCommand& aCommand)
    {
    if ( !aCommand.IsSupported(aAttribute) )
    	{
        User::Leave(KErrArgument); 	
    	}
    return aCommand.ValueTObjectL<T>(aAttribute);
    }
/// @todo minor: Rowland Cook 12/06/2007 Add method decription.
// -----------------------------------------------------------------------------
// TGlxCommandFactory::AddContainerCommandLC
// -----------------------------------------------------------------------------
//	
EXPORT_C CMPXCommand* TGlxCommandFactory::AddContainerCommandLC(const TDesC& aTitle, 
        TInt aCollectionUid)
    {
    CMPXCommand* command = CMPXCommand::NewL();
    CleanupStack::PushL(command);
    
    // Add collection plugin id to command object
    command->SetTObjectValueL<TUid>(KMPXCommandGeneralCollectionId, TUid::Uid(aCollectionUid));        
    
    // Set command id
    command->SetTObjectValueL<TInt>(KMPXCommandGeneralId, KGlxCommandIdAdd);    

    // Set title of new object
    command->SetTextValueL(KMPXMediaGeneralTitle, aTitle);        
    
    return command;
    }
/// @todo minor: Rowland Cook 12/06/2007 Add method decription.
// -----------------------------------------------------------------------------
// TGlxCommandParser::IdsL
// -----------------------------------------------------------------------------
//	
EXPORT_C TBool TGlxCommandParser::IdsL(TUid& aCollectionUid, TUint32& aSessionId, const CMPXCommand& aCommand)
    {	
	aCollectionUid = ValueL<TUid>(KMPXCommandGeneralCollectionId, aCommand);    
    if ( aCommand.IsSupported(KMPXCommandGeneralSessionId) )
    	{
    	aSessionId = aCommand.ValueTObjectL<TUint32>(KMPXCommandGeneralSessionId);
    	return ETrue;
    	}
    else
    	{
    	return EFalse;
    	}
    }
/// @todo minor: Rowland Cook 12/06/2007 Add method decription.
// -----------------------------------------------------------------------------
// TTGlxCommandParser::ArrayValueL
// -----------------------------------------------------------------------------
//	
void TGlxCommandParser::ArrayValueL(const TMPXAttribute & aAttribute, RArray<TGlxMediaId>& aArray, const CMPXCommand& aCommand)
    {
    if (!aCommand.IsSupported(aAttribute) || aCommand.Type(aAttribute) != EMPXTypeCObject)
        {
        User::Leave(KErrArgument);
        }
  
    const CMPXCollectionPath* path = aCommand.ValueCObjectL<CMPXCollectionPath>(aAttribute);
	RArray<TMPXItemId> list;
    path->SelectionL(list);
  
    if (list.Count() == 0) // append the current item
        {
        aArray.AppendL(TGlxMediaId(path->Id())); 
        } 
    else
    	{
    	for( TInt i = 0 ; i < list.Count() ; i++ )
    		{
    		aArray.AppendL(TGlxMediaId(list[i]));
    		}
    	}
    }
// ---------------------------------------------------------------------------
// rename a media object
// ---------------------------------------------------------------------------
//
void CMPXCollectionHelperImp::RenameL( const TDesC& aOldUri,
                                       const TDesC& aNewUri,
                                       TMPXGeneralCategory aItemCat )
    {
    MPX_FUNC("CMPXCollectionHelperImp::RenameL");
    MPX_DEBUG3("aOldUri = %S, aNewUri = %S", &aOldUri, &aNewUri);

    if (aItemCat != EMPXSong && aItemCat != EMPXPlaylist && aItemCat != EMPXAbstractAlbum)
        {
        User::Leave(KErrArgument);
        }

    // find the media using the old URI
    RArray<TMPXAttribute> attributes;
    CleanupClosePushL( attributes );
    attributes.AppendL(KMPXMediaGeneralId);
    attributes.AppendL(KMPXMediaMusicAlbumArtFileName);

    CMPXMedia* media = GetL(aOldUri, attributes.Array(), aItemCat);
    CleanupStack::PopAndDestroy(&attributes);
    CleanupStack::PushL(media);

    const TDesC& fileName(media->ValueText(KMPXMediaMusicAlbumArtFileName));
    
    // the songs have embedded albumart.
    if(fileName.CompareF(aOldUri) == 0)
        {
        // change the Art filename to the new Uri
        media->SetTextValueL(KMPXMediaMusicAlbumArtFileName, aNewUri);
        
        // Rename the thumbnail
        TRAPD(err, RenameThumbnailL(aOldUri, aNewUri));
        if(KErrNone != err)
            {
            MPX_DEBUG2("Thumbnail renames failed. Err: %d", err);
            }
        }

    // change file path to the new file path
    media->SetTextValueL(KMPXMediaGeneralUri, aNewUri);

    // ask harvester to rename the file if any of the following is true:
    // 1) renaming a song
    // 2) renaming a playlist scanned through file system.
    //
    //    There are 3 types of playlists. The ones created from the device
    //    are virtual playlists which have file extension .vir. There are
    //    no physical playlist files associated with them; hence not
    //    registered with harvester. For virtual playlists, IsPlaylistL
    //    will return EFalse because there is not a playlist plugin that
    //    deals with .vir playlist files.
    //
    //    The ones synced from PC through MTP have file extension .pla.
    //    There are 0-byte .pla files associated with them but they
    //    are not registered with harvester either. IsPlaylistL will also
    //    return EFalse because there is not a playlist plugin that deals
    //    with .pla.
    //
    //    The 3rd type of playlists is .m3u on the file system. They are
    //    added to the collection through file scan and registered with
    //    harvester. IsPlaylistL will return ETrue.
    if (aItemCat == EMPXSong || iHvsUtility->IsPlaylistL(aOldUri))
        {
        const TUid& collection =
             media->ValueTObjectL<TUid>(KMPXMediaGeneralCollectionId);
        iHvsUtility->RenameFileL( aOldUri, aNewUri, collection.iUid );
        }

    // Update collection via CMPXCommand
    //
    CMPXCommand* cmd = CMPXCommand::NewL();
    CleanupStack::PushL( cmd );
    cmd->SetTObjectValueL( KMPXCommandGeneralId, KMPXCommandIdCollectionSet );
    TUid colId (media->ValueTObjectL<TUid>(KMPXMediaGeneralCollectionId) );
    cmd->SetTObjectValueL( KMPXCommandGeneralCollectionId, colId.iUid );
    cmd->SetTObjectValueL( KMPXCommandGeneralDoSync, ETrue );
    cmd->SetCObjectValueL( KMPXCommandColSetMedia, media );
    iCollectionUtil->Collection().CommandL( *cmd );
    CleanupStack::PopAndDestroy( cmd );

    CleanupStack::PopAndDestroy(media);
    }
// ---------------------------------------------------------------------------
// Remove a file from the collection
// ---------------------------------------------------------------------------
//
void CMPXCollectionHelperImp::RemoveL( const TDesC& aFile,
                                       TMPXGeneralCategory aItemCat )
    {
    MPX_FUNC("CMPXCollectionHelperImp::RemoveL");
    MPX_DEBUG3("aFile %S, category %d", &aFile, aItemCat);

    if (aItemCat != EMPXSong && aItemCat != EMPXPlaylist)
        {
        User::Leave(KErrArgument);
        }

    //
    // ask harvester to remove the file if any of the following is true:
    // 1) removing a song
    // 2) removing a playlist scanned through file system.
    //
    //    There are 3 types of playlists. The ones created from the device
    //    are virtual playlists which have file extension .vir. There are
    //    no physical playlist files associated with them; hence not
    //    registered with harvester. For virtual playlists, IsPlaylistL
    //    will return EFalse because there is not a playlist plugin that
    //    deals with .vir playlist files.
    //
    //    The ones synced from PC through MTP have file extension .pla.
    //    There are 0-byte .pla files associated with them but they
    //    are not registered with harvester either. IsPlaylistL will also
    //    return EFalse because there is not a playlist plugin that deals
    //    with .pla.
    //
    //    The 3rd type of playlists is .m3u on the file system. They are
    //    added to the collection through file scan and registered with
    //    harvester. IsPlaylistL will return ETrue.
    //
    //    For now virtual playlists and synced playlists are assumed to
    //    be in the music collection for now until there is a generic way
    //    resolving collections aside from using file extension or UID.
    //
    TInt collection(iMusicCollectionId.iUid);
    if (aItemCat == EMPXSong || iHvsUtility->IsPlaylistL(aFile))
        {
        // Remove from the harvester
        collection = iHvsUtility->RemoveFileL( aFile );
        }

    // Remove from the collection
    // Construct a CMPXMedia object with URI, collection id, type and category
    //
    RArray<TInt> contID;
    CleanupClosePushL( contID );
    contID.AppendL( KMPXMediaIdGeneral );
    CMPXMedia* media = CMPXMedia::NewL( contID.Array() );
    CleanupStack::PushL( media );

    media->SetTextValueL( KMPXMediaGeneralUri, aFile );
    media->SetTObjectValueL<TUid>( KMPXMediaGeneralCollectionId, TUid::Uid( collection ) );
    media->SetTObjectValueL( KMPXMediaGeneralType, EMPXItem );
    media->SetTObjectValueL( KMPXMediaGeneralCategory, aItemCat );

    // Remove the item via CMPXCommand
    //
    CMPXCommand* cmd = CMPXCommand::NewL();
    CleanupStack::PushL( cmd );
    cmd->SetTObjectValueL( KMPXCommandGeneralCollectionId,
                           collection );
    cmd->SetTObjectValueL( KMPXCommandGeneralId,
                           KMPXCommandIdCollectionRemoveMedia );
    cmd->SetTObjectValueL( KMPXCommandGeneralDoSync, ETrue );
    cmd->SetCObjectValueL( KMPXCommandCollectionRemoveMedia, media );
    cmd->SetTObjectValueL( KMPXCommandCollectionRemoveMediaDeleteRecord,
                           ETrue );
    iCollectionUtil->Collection().CommandL( *cmd );
    CleanupStack::PopAndDestroy( cmd );

    CleanupStack::PopAndDestroy( media );
    CleanupStack::PopAndDestroy( &contID );
    }
/// @todo minor: Rowland Cook 12/06/2007 Add method decription.
// -----------------------------------------------------------------------------
// TGlxCommandParser::ParseL
// -----------------------------------------------------------------------------
//	
EXPORT_C void TGlxCommandParser::ParseL(MGlxCommandParserCallback& aCommandHandler, const CMPXCommand& aCommand)
    {
    TUint32 commandId = ValueL<TUint32>(KMPXCommandGeneralId, aCommand);

    RArray<TGlxMediaId> sourceIdArray;
    CleanupClosePushL(sourceIdArray);
  
    RArray<TGlxMediaId> targetIdArray;
    CleanupClosePushL(targetIdArray);
  
    switch (commandId)
        {
        case KGlxCommandIdAdd:
            { 
            TBool hasTitle = aCommand.IsSupported(KMPXMediaGeneralTitle);
            TBool hasSourceIds = aCommand.IsSupported(KMPXCommandGeneralSourceIds);
            TBool hasUri = aCommand.IsSupported(KMPXCommandGeneralSourceUri);
            TBool hasTargetIds = aCommand.IsSupported(KMPXMediaGeneralContainerId);
            TBool hasDrive = aCommand.IsSupported(KMPXMediaGeneralDrive);
        
            if (hasSourceIds)
                {            
                ArrayValueL(KMPXCommandGeneralSourceIds, sourceIdArray, aCommand);
                }
            if (hasTargetIds)
                {
                ArrayValueL(KMPXMediaGeneralContainerId, targetIdArray, aCommand);  
                }

/// @todo minor: Rowland Cook 12/06/2007 Could this be restrctured to be more efficient?
//                                       IE - Test for invalid combiations before retrieving the data. 
            
            if(hasTitle)
                {
                if(hasUri || hasSourceIds || hasDrive || hasTargetIds)
                    {
                    User::Leave(KErrArgument);
                    }
                aCommandHandler.AddContainerL(DescriptorValueL(KMPXMediaGeneralTitle, aCommand));
                }
            else if (hasUri)
                {
                if (hasSourceIds || hasDrive || !hasTargetIds)
                    // Illegal parameter combination
                    {
                    User::Leave(KErrArgument);
                    }
                aCommandHandler.AddToContainerL(DescriptorValueL(KMPXCommandGeneralSourceUri, aCommand), targetIdArray);   
                }
            else if (hasSourceIds)
                {
                if (hasTargetIds)
                    {
                    if (hasDrive)
                    	// Illegal parameter combination
                    	{
                    	User::Leave(KErrArgument);
                    	}
                    aCommandHandler.AddToContainerL(sourceIdArray, targetIdArray);
                    }
                else if (hasDrive)
                    {
                    aCommandHandler.CopyL(sourceIdArray, DescriptorValueL(KMPXMediaGeneralDrive, aCommand));
                    }
                else
                    // There isn't a target
                    {
                    User::Leave(KErrArgument);
                    }
                }
            else // There isn't a source
                {
                User::Leave(KErrArgument);
                }
            break;
            }
        case KGlxCommandIdRemove:
            {
            ArrayValueL(KMPXCommandGeneralSourceIds, sourceIdArray, aCommand);  
            TGlxMediaId containerId (ValueL<TMPXItemId>(KMPXMediaGeneralContainerId, aCommand));
            if (containerId == KGlxContainerDevice)
            	{
            	aCommandHandler.DeleteL(sourceIdArray);
            	}
            else
            	{
            	aCommandHandler.RemoveFromContainerL(sourceIdArray, containerId);
            	}
            break;
            }
        case KGlxCommandIdSet:
            {    
            TBool hasTitle = aCommand.IsSupported(KMPXMediaGeneralTitle);
            TBool hasDrive = aCommand.IsSupported(KMPXMediaGeneralDrive);
            TBool hasComment = aCommand.IsSupported(KMPXMediaGeneralComment);
            TBool hasLocation = aCommand.IsSupported(KGlxMediaGeneralLocation);
            
            ArrayValueL(KMPXCommandGeneralSourceIds, sourceIdArray, aCommand);
            
            if (hasTitle)
                // Rename operation
                {
                if (hasDrive || hasComment || hasLocation || sourceIdArray.Count() < 1)
                    // Unsupported attribute combination
                    {
                    User::Leave(KErrArgument);
                    }
                 const TDesC& title = DescriptorValueL(KMPXMediaGeneralTitle, aCommand);
                 aCommandHandler.RenameL(sourceIdArray[0], title);
                }
            else if (hasDrive)
                {
                if(hasComment  || hasLocation)
                    // Unsupported attribute combination
                    {
                    User::Leave(KErrArgument);
                    }
                const TDesC& drive = DescriptorValueL(KMPXMediaGeneralDrive, aCommand);
                aCommandHandler.MoveL(sourceIdArray, drive);
                }
            else if (hasComment)
                {
                if ( hasLocation )
                    // Unsupported attribute combination
                    {
                    User::Leave(KErrArgument);
                    }
                const TDesC& comment = DescriptorValueL(KMPXMediaGeneralComment, aCommand);
                aCommandHandler.SetDescriptionL(sourceIdArray, comment);
                }
            else if (hasLocation)
            	{
            	TCoordinate coordinate = aCommand.ValueTObjectL<TCoordinate>(KGlxMediaGeneralLocation);
            	aCommandHandler.SetCaptureLocationL(sourceIdArray, coordinate);
            	}
            else
            	{
                
                User::Leave(KErrArgument);
            	}
            break;
            }
        case KGlxCommandThumbnailCleanup:
        	{
        	aCommandHandler.ThumbnailCleanupL();
        	break;
        	}
        }
        CleanupStack::PopAndDestroy(&targetIdArray); 
        CleanupStack::PopAndDestroy(&sourceIdArray);
 
    }
// ----------------------------------------------------------------------------------------------------------
// Executes the given command on the collection
// ----------------------------------------------------------------------------------------------------------
//
void CTestCollectionPlugin::CommandL(CMPXCommand& aCmd)
{
    LOG1(_L("CTestCollectionPlugin::CommandL"));
    const TDesC& title = aCmd.ValueText( KMPXMediaGeneralTitle );
    TMPXCommandId cmdId = aCmd.ValueTObjectL<TMPXCommandId>(KMPXCommandGeneralId);
    LOG2(_L("CommandId = %d"), cmdId);

    if(title == _L("CollectionPluginTest0175") )
    {
    }
    else if(title == _L("CollectionPluginTest0176") )
    {
        iObs->HandleCommandComplete(NULL, KErrNone);
    }
    else if(title == _L("CollectionPluginTest0177") )
    {
        iObs->HandleCommandComplete(NULL, KErrGeneral);
    }
    else if(title == _L("CollectionPluginTest0183") )
    {
    }
    else if(title == _L("CollectionPluginTest0184") )
    {
        CMPXCommand* newCmd = CMPXCommand::NewL();
        CleanupStack::PushL( newCmd );
        *newCmd = aCmd;
        iObs->HandleCommandComplete(newCmd, KErrNone);
        CleanupStack::PopAndDestroy( newCmd );
    }
    else
    {
        TBool syncOp(EFalse);
        if( aCmd.IsSupported(KMPXCommandGeneralDoSync) )
        {
            syncOp = *aCmd.Value<TBool>(KMPXCommandGeneralDoSync);
        }

        switch( cmdId )
        {
        case KMPXCommandIdCollectionRetrieveUriForDeletion:
        {   // TODO
            LOG1(_L("CTestCollectionPlugin::CommandL - KMPXCommandIdCollectionRetrieveUriForDeletion"));
            //DoRetrieveUriForDeletionL(aCmd);
            break;
        }
        case KMPXCommandIdCollectionRemove:
        {
            LOG1(_L("CTestCollectionPlugin::CommandL - KMPXCommandIdCollectionRemove"));
            //DoRemovePathL(aCmd);
            break;
        }
        case KMPXCommandIdCollectionRemoveMedia:
        {
            LOG1(_L("CTestCollectionPlugin::CommandL - KMPXCommandIdCollectionRemoveMedia"));
            //DoRemoveMediaL(aCmd);
            break;
        }
        case KMPXCommandIdCollectionCleanupDeletedMedias:
        {
            LOG1(_L("CTestCollectionPlugin::CommandL - KMPXCommandIdCollectionCleanupDeletedMedias"));
            //DoCleanupDeletedMediasL(aCmd);
            break;
        }
        case KMPXCommandIdCollectionAdd:
        {
            LOG1(_L("CTestCollectionPlugin::CommandL - KMPXCommandIdCollectioAdd"));

            CMPXMedia& media = *aCmd.Value<CMPXMedia>(KMPXCommandColAddMedia);
            AddL(media);
            break;
        }
        case KMPXCommandIdCollectionSet:
        {
            LOG1(_L("CTestCollectionPlugin::CommandL - KMPXCommandIdCollectionSet"));

            CMPXMedia& media = *aCmd.Value<CMPXMedia>(KMPXCommandColSetMedia);
            SetL( media );
            break;
        }
        case KMPXCommandIdCollectionCompleteDelete:
        {
            LOG1(_L("CTestCollectionPlugin::CommandL - KMPXCommandIdCollectionCompleteDelete"));
            //DoHandleDeleteCompleteL( aCmd );
            break;
        }
        default:
        {
            User::Panic(_L("CTestCollectionPlugin::CommandL panic"), 1); // magic number
        }
        }
        if (!syncOp)
        {
            iObs->HandleCommandComplete( NULL, KErrNone );
        }
    }
}