/*
 * Copyright © 2007-2009 Stephan Aßmus <superstippi@gmx.de>
 * All rights reserved. Distributed under the terms of the MIT license.
 */
 
#include "RemovePLItemsCommand.h"
 
#include <new>
#include <stdio.h>
 
#include <Alert.h>
#include <Autolock.h>
#include <Catalog.h>
#include <Locale.h>
 
#include "Playlist.h"
 
 
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "MediaPlayer-RemovePLItemsCmd"
 
 
using std::nothrow;
 
 
RemovePLItemsCommand::RemovePLItemsCommand(Playlist* playlist,
		 const int32* indices, int32 count, bool moveFilesToTrash)
	:
	PLItemsCommand(),
	fPlaylist(playlist),
	fItems(count > 0 ? new (nothrow) PlaylistItem*[count] : NULL),
	fIndices(count > 0 ? new (nothrow) int32[count] : NULL),
	fCount(count),
	fMoveFilesToTrash(moveFilesToTrash),
	fMoveErrorShown(false),
	fItemsRemoved(false)
{
	if (!indices || !fPlaylist || !fItems || !fIndices) {
		// indicate a bad object state
		delete[] fItems;
		fItems = NULL;
		return;
	}
 
	memcpy(fIndices, indices, fCount * sizeof(int32));
	memset(fItems, 0, fCount * sizeof(PlaylistItem*));
 
	// init original entry indices
	for (int32 i = 0; i < fCount; i++) {
		fItems[i] = fPlaylist->ItemAt(fIndices[i]);
		if (fItems[i] == NULL) {
			delete[] fItems;
			fItems = NULL;
			return;
		}
	}
}
 
 
RemovePLItemsCommand::~RemovePLItemsCommand()
{
	_CleanUp(fItems, fCount, fItemsRemoved);
	delete[] fIndices;
}
 
 
status_t
RemovePLItemsCommand::InitCheck()
{
	if (!fPlaylist || !fItems || !fIndices)
		return B_NO_INIT;
	return B_OK;
}
 
 
status_t
RemovePLItemsCommand::Perform()
{
	BAutolock _(fPlaylist);
 
	fItemsRemoved = true;
 
	int32 lastRemovedIndex = -1;
 
	// remove refs from playlist
	for (int32 i = 0; i < fCount; i++) {
		// "- i" to account for the items already removed
		lastRemovedIndex = fIndices[i] - i;
		fPlaylist->RemoveItem(lastRemovedIndex);
	}
 
	// in case we removed the currently playing file
	if (fPlaylist->CurrentItemIndex() == -1)
		fPlaylist->SetCurrentItemIndex(lastRemovedIndex);
 
	if (fMoveFilesToTrash) {
		BString errorFiles;
		status_t moveError = B_OK;
		bool errorOnAllFiles = true;
		for (int32 i = 0; i < fCount; i++) {
			status_t err = fItems[i]->MoveIntoTrash();
			if (err != B_OK) {
				moveError = err;
				if (errorFiles.Length() > 0)
					errorFiles << ' ';
				errorFiles << fItems[i]->Name();
			} else
				errorOnAllFiles = false;
		}
		// Show an error alert if necessary
		if (!fMoveErrorShown && moveError != B_OK) {
			fMoveErrorShown = true;
			BString message;
			if (errorOnAllFiles)
				message << 
					B_TRANSLATE("All files could not be moved into Trash.");
			else
				message << 
					B_TRANSLATE("Some files could not be moved into Trash.");
			message << "\n\n" << B_TRANSLATE("Error: ") << strerror(moveError);
			BAlert* alert = new BAlert(B_TRANSLATE("Move into trash error"),
				message.String(), B_TRANSLATE("OK"), NULL, NULL,
				B_WIDTH_AS_USUAL, B_WARNING_ALERT);
			alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
			alert->Go(NULL);
		}
	}
 
	return B_OK;
}
 
 
status_t
RemovePLItemsCommand::Undo()
{
	BAutolock _(fPlaylist);
 
	fItemsRemoved = false;
 
	if (fMoveFilesToTrash) {
		for (int32 i = 0; i < fCount; i++) {
			fItems[i]->RestoreFromTrash();
		}
	}
 
	// remember currently playling item in case we move it
	PlaylistItem* current = fPlaylist->ItemAt(fPlaylist->CurrentItemIndex());
 
	// add items to playlist at remembered indices
	status_t ret = B_OK;
	for (int32 i = 0; i < fCount; i++) {
		if (!fPlaylist->AddItem(fItems[i], fIndices[i])) {
			ret = B_NO_MEMORY;
			break;
		}
	}
	if (ret < B_OK)
		return ret;
 
	// take care about currently played ref
	if (current != NULL)
		fPlaylist->SetCurrentItemIndex(fPlaylist->IndexOf(current), false);
 
	return B_OK;
}
 
 
void
RemovePLItemsCommand::GetName(BString& name)
{
	if (fMoveFilesToTrash) {
		if (fCount > 1)
			name << B_TRANSLATE("Remove Entries into Trash");
		else
			name << B_TRANSLATE("Remove Entry into Trash");
	}
	else
	{	
		if (fCount > 1)
			name << B_TRANSLATE("Remove Entries");
		else
			name << B_TRANSLATE("Remove Entry");
	}
}

V773 Visibility scope of the 'alert' pointer was exited without releasing the memory. A memory leak is possible.