1 package org.musicontroller;
2
3 import java.util.LinkedList;
4 import java.util.List;
5 import java.util.concurrent.CopyOnWriteArrayList;
6
7 import org.apache.log4j.Logger;
8 import org.musicontroller.core.Band;
9 import org.musicontroller.core.Event;
10 import org.musicontroller.core.Keyword;
11 import org.musicontroller.core.Keywordbag;
12 import org.musicontroller.core.Song;
13 import org.musicontroller.security.IUser;
14 import org.musicontroller.songselection.CandidateSelector;
15 import org.musicontroller.songselection.LastPlayedContainer;
16 import org.musicontroller.songselection.SongSelector;
17
18 public class DJImpl implements DJ, SongChangeListener {
19 private static Logger LOG = Logger.getLogger(DJImpl.class);
20
21 private static MusiController _musicontroller;
22 private SongSelector _songselector;
23 private CandidateSelector _candidateselector;
24 private List<Long> _requests;
25 private List<Long> _prediction;
26 private IUser _user;
27 private boolean _mustskip;
28 private long _nextMandatoryRequest;
29 private boolean _playing;
30 private LastPlayedContainer _lastplayed;
31
32
33
34 private Song _currentSong;
35 private int _millisecondsplayed;
36
37 public DJImpl() {
38 _requests = new CopyOnWriteArrayList<Long>();
39 _user = null;
40 _mustskip = false;
41 _nextMandatoryRequest = -1L;
42 _playing = false;
43 _prediction = null;
44 _lastplayed = new LastPlayedContainer();
45 _currentSong = new Song();
46 _currentSong.setBand(new Band());
47 }
48
49
50
51
52
53 public void setPlaying(boolean playing) {
54 _playing = playing;
55 }
56
57
58
59
60
61 public void setMusiController(MusiController musicontroller) {
62 _musicontroller = musicontroller;
63 }
64
65
66
67
68
69 public MusiController getMusiController() {
70 return _musicontroller;
71 }
72
73
74
75
76
77 public SongSelector getSongSelector() {
78 return _songselector;
79 }
80
81
82
83
84
85 public void setSongSelector(SongSelector selector) {
86 this._songselector = selector;
87 }
88
89
90
91
92
93 public CandidateSelector getCandidateSelector() {
94 return _candidateselector;
95 }
96
97
98
99
100
101 public void setCandidateSelector(CandidateSelector selector) {
102 _candidateselector = selector;
103 }
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118 private List<Song> selectCandidates(final List<Long> requests) {
119
120 List<Long> reqs;
121 if (_nextMandatoryRequest!=-1L) {
122 reqs = new LinkedList<Long>();
123 reqs.add(_nextMandatoryRequest);
124 } else {
125 if (_prediction!=null && _prediction.size()>0) {
126
127 reqs = new LinkedList<Long>();
128 reqs.add(_prediction.get(0));
129 _prediction.remove(0);
130 } else {
131 reqs = requests;
132 }
133 }
134 return _candidateselector.selectCandidates(reqs);
135 }
136
137
138
139
140
141
142
143 public synchronized Song choose() {
144 if(getUser()==null) {
145 LOG.error("DJ has no user attached. The DJ can not play songs.");
146 return null;
147 }
148 if(getMusiController()==null) {
149 LOG.error("DJ for user "+getUser().getName()+" has no MusiController attached. The DJ can not play songs.");
150 return null;
151 }
152 Song song = null;
153 try {
154 song = _songselector.selectSong(selectCandidates(_requests),_lastplayed,_user);
155 _nextMandatoryRequest=-1L;
156
157 if(song!=null) {
158 _lastplayed.addToLastPlayed(song.getId());
159 _candidateselector.removeFromCandidates(song);
160 removeFromRequestsandPredictions(song.getId());
161 setCurrentSong(song);
162 }
163 } catch (Exception e) {
164 LOG.error(e);
165 }
166 return song;
167 }
168
169
170
171
172
173
174 private void setCurrentSong(Song song) {
175 _currentSong.setId(song.getId());
176 _currentSong.setName(song.getName());
177 _currentSong.getBand().setId(song.getBand().getId());
178 _currentSong.getBand().setName(song.getBand().getName());
179 _currentSong.setLength(song.getLength());
180
181 List<Keyword> currentKeywords = new LinkedList<Keyword>();
182 if (song.getKeywordbag()!=null) {
183 for(Keyword kw : song.getKeywordbag().getKeywords()) {
184 Keyword currentkw = new Keyword();
185 currentkw.setId(kw.getId());
186 currentkw.setName(kw.getName());
187 currentKeywords.add(kw);
188 }
189 }
190 Keywordbag currentKeywordbag = new Keywordbag();
191 currentKeywordbag.setKeywords(currentKeywords);
192 _currentSong.setKeywordbag(currentKeywordbag);
193 }
194
195
196
197
198
199
200
201 private void markAsPlayed(long songid) {
202 getMusiController().saveSongEvent(songid,Event.played,_user.getId());
203 _songselector.addBandPlay(_currentSong.getBand().getId());
204 for (Keyword kw : _currentSong.getKeywordbag().getKeywords()) {
205 _songselector.addKeywordPlay(kw.getId());
206 }
207 }
208
209
210
211
212
213
214
215 private void markAsSkipped(long songid) {
216 _lastplayed.markLastSongAsSkipped();
217 getMusiController().saveSongEvent(songid,Event.skipped,_user.getId());
218 _songselector.addBandSkip(_currentSong.getBand().getId());
219 for (Keyword kw : _currentSong.getKeywordbag().getKeywords()) {
220 _songselector.addKeywordSkip(kw.getId());
221 }
222 }
223
224
225
226
227
228
229 private void markAsRequested(long songid) {
230 getMusiController().saveSongEvent(songid,Event.requested,_user.getId());
231 }
232
233
234
235
236
237
238
239 public synchronized void requestSong(long songid) {
240 if(_user==null) {
241 LOG.info("Song request denied: user not logged on.");
242 return;
243 }
244 _requests.add(songid);
245 markAsRequested(songid);
246 _prediction = null;
247 }
248
249
250
251
252
253
254
255 public synchronized void unrequestSong(long songid) {
256 removeFromRequestsandPredictions(songid);
257 markAsSkipped(songid);
258 }
259
260
261
262
263
264
265 private void removeFromRequestsandPredictions(long songid) {
266 _requests.remove(songid);
267
268 if (_prediction!=null) {
269
270
271
272 _prediction.remove(songid);
273 }
274 }
275
276
277
278
279
280 public void skipSong() {
281 _mustskip = true;
282 }
283
284
285
286
287
288 public boolean mustSkip() {
289 return _mustskip;
290 }
291
292
293
294
295
296 public void confirmSkip() {
297 _mustskip = false;
298 markAsSkipped(_currentSong.getId());
299 }
300
301
302
303
304
305 public void confirmPlay() {
306 markAsPlayed(_currentSong.getId());
307 }
308
309
310
311
312
313 public void playSong(long songid) {
314 _nextMandatoryRequest = songid;
315 skipSong();
316 }
317
318
319
320
321
322 public List<Long> getRequests() {
323 return _requests;
324 }
325
326
327
328
329
330 public void setUser(IUser user) {
331 _user = user;
332 }
333
334
335
336
337
338 public IUser getUser() {
339 return _user;
340 }
341
342
343
344
345
346 public Song getCurrentSong() {
347 return _playing ? _currentSong : null;
348 }
349
350
351
352
353
354
355
356
357
358 public synchronized List<Long> peek(int count) {
359 List<Long> prediction = _prediction==null ? new LinkedList<Long>() : _prediction;
360
361
362 count = Math.max(count, _requests.size());
363
364 int toPredict = count - prediction.size();
365 if (toPredict==0) return _prediction;
366 LOG.debug("Asked for "+toPredict+" new predictions.");
367
368
369 List<Long> requestsCopy = new LinkedList<Long>();
370 for (Long l : _requests) {
371 if (!prediction.contains(l)) requestsCopy.add(l);
372 }
373
374 LastPlayedContainer lastplayedCopy = null;
375 try {
376 lastplayedCopy = _lastplayed.clone();
377 } catch (CloneNotSupportedException e) {
378 LOG.error("Error cloning lastplayedcontainer, continueing with a new one : " + e);
379 lastplayedCopy = new LastPlayedContainer();
380 }
381
382 for (Long l : prediction) {
383 lastplayedCopy.addToLastPlayed(l);
384 }
385
386 _prediction=null;
387
388
389 while (requestsCopy.size()>0) {
390 Song song = getSongSelector().selectSong(selectCandidates(requestsCopy),lastplayedCopy,_user);
391 if (song!=null) {
392 lastplayedCopy.addToLastPlayed(song.getId());
393 requestsCopy.remove(song.getId());
394 prediction.add(song.getId());
395 }
396 toPredict--;
397 }
398
399 if (toPredict>0) {
400
401
402
403 int toSelect = Math.min(100, _candidateselector.getCandidateCount()*toPredict);
404 List<Song> candidates = _candidateselector.selectCandidates(toSelect);
405 while (toPredict>0) {
406 Song song = getSongSelector().selectSong(candidates,lastplayedCopy,_user);
407 if (song!=null) {
408 lastplayedCopy.addToLastPlayed(song.getId(), true);
409 requestsCopy.remove(song.getId());
410 prediction.add(song.getId());
411 candidates.remove(song);
412 }
413 toPredict--;
414 }
415 }
416 _prediction = prediction;
417
418 return _prediction;
419 }
420
421
422
423
424
425 public void setPlayingTime(int millis) {
426 _millisecondsplayed = millis;
427 }
428
429
430
431
432
433 public int getPlayingTime() {
434 return _millisecondsplayed;
435 }
436
437
438
439
440
441 public void onSongAdded(Song song) {
442 _candidateselector.addToCandidates(song);
443 }
444
445
446
447
448
449 public void onSongChanged(Song song) {
450 if (_currentSong.getId()==song.getId()) {
451 setCurrentSong(song);
452 }
453 }
454
455
456
457
458
459
460
461 public synchronized void onSongDeleted(Song song) {
462 _candidateselector.removeFromCandidates(song);
463 removeFromRequestsandPredictions(song.getId());
464 }
465
466 }