1/*
2 * Copyright �� 2008-2009 Stephan A��mus <superstippi@gmx.de>
3 * All rights reserved. Distributed under the terms of the MIT License.
4 */
5
6#include "RandomizePLItemsCommand.h"
7
8#include <new>
9#include <stdio.h>
10#include <stdlib.h>
11
12#include <Autolock.h>
13#include <Catalog.h>
14#include <Locale.h>
15
16#include "Playlist.h"
17
18
19#undef B_TRANSLATION_CONTEXT
20#define B_TRANSLATION_CONTEXT "MediaPlayer-RandomizePLItemsCmd"
21
22
23using std::nothrow;
24
25
26RandomizePLItemsCommand::RandomizePLItemsCommand(Playlist* playlist,
27		 BList indices)
28	:
29	PLItemsCommand(),
30	fPlaylist(playlist),
31	fCount(indices.CountItems()),
32	fItems(fCount > 0 ? new (nothrow) PlaylistItem*[fCount] : NULL),
33	fListIndices(fCount > 0 ? new (nothrow) int32[fCount] : NULL),
34	fRandomInternalIndices(fCount > 0 ? new (nothrow) int32[fCount] : NULL)
35{
36	if (indices.IsEmpty() || !fPlaylist || !fItems || !fListIndices
37			|| !fRandomInternalIndices) {
38		// indicate a bad object state
39		delete[] fItems;
40		fItems = NULL;
41		return;
42	}
43
44	memset(fItems, 0, fCount * sizeof(PlaylistItem*));
45
46	// put the available indices into a "set"
47	BList indexSet;
48	for (int32 i = 0; i < fCount; i++) {
49		fListIndices[i] = (int32)(addr_t)indices.ItemAt(i);
50		fItems[i] = fPlaylist->ItemAt(fListIndices[i]);
51		if (fItems[i] == NULL || !indexSet.AddItem((void*)(addr_t)i)) {
52			// indicate a bad object state
53			delete[] fItems;
54			fItems = NULL;
55			return;
56		}
57	}
58
59	// remove the indices from the set in random order
60	for (int32 i = 0; i < fCount; i++) {
61		int32 randomSetIndex = rand() % indexSet.CountItems();
62		fRandomInternalIndices[i] = (int32)(addr_t)indexSet.RemoveItem(randomSetIndex);
63	}
64}
65
66
67RandomizePLItemsCommand::~RandomizePLItemsCommand()
68{
69	delete[] fItems;
70	delete[] fListIndices;
71	delete[] fRandomInternalIndices;
72}
73
74
75status_t
76RandomizePLItemsCommand::InitCheck()
77{
78	if (!fItems)
79		return B_NO_INIT;
80
81	return B_OK;
82}
83
84
85status_t
86RandomizePLItemsCommand::Perform()
87{
88	return _Sort(true);
89}
90
91
92status_t
93RandomizePLItemsCommand::Undo()
94{
95	return _Sort(false);
96}
97
98
99void
100RandomizePLItemsCommand::GetName(BString& name)
101{
102	name << B_TRANSLATE("Randomize Entries");
103}
104
105
106status_t
107RandomizePLItemsCommand::_Sort(bool random)
108{
109	BAutolock _(fPlaylist);
110
111	// remember currently playling item in case we move it
112	PlaylistItem* current = fPlaylist->ItemAt(fPlaylist->CurrentItemIndex());
113
114	// remove refs from playlist
115	for (int32 i = 0; i < fCount; i++) {
116		// "- i" to account for the items already removed
117		fPlaylist->RemoveItem(fListIndices[i] - i, false);
118	}
119
120	// add refs to playlist at the randomized indices
121	if (random) {
122		for (int32 i = 0; i < fCount; i++) {
123			if (!fPlaylist->AddItem(fItems[fRandomInternalIndices[i]],
124					fListIndices[i])) {
125				return B_NO_MEMORY;
126			}
127		}
128	} else {
129		for (int32 i = 0; i < fCount; i++) {
130			if (!fPlaylist->AddItem(fItems[i], fListIndices[i])) {
131				return B_NO_MEMORY;
132			}
133		}
134	}
135
136	// take care about currently played item
137	if (current != NULL)
138		fPlaylist->SetCurrentItemIndex(fPlaylist->IndexOf(current), false);
139
140	return B_OK;
141}
142