/* * Copyright 2008-2013, ETH Zürich, Samuel Welten, Michael Kuhn, Tobias Langner, * Sandro Affentranger, Lukas Bossard, Michael Grob, Rahul Jain, * Dominic Langenegger, Sonia Mayor Alonso, Roger Odermatt, Tobias Schlueter, * Yannick Stucki, Sebastian Wendland, Samuel Zehnder, Samuel Zihlmann, * Samuel Zweifel * * This file is part of Jukefox. * * Jukefox is free software: you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation, either version 3 of the License, or any later version. Jukefox is * distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along with * Jukefox. If not, see <http://www.gnu.org/licenses/>. */ package ch.ethz.dcg.jukefox.controller.player.playlistmanager; import java.util.LinkedList; import java.util.List; import ch.ethz.dcg.jukefox.commons.Constants; import ch.ethz.dcg.jukefox.commons.utils.Log; import ch.ethz.dcg.jukefox.controller.player.IOnPlaylistStateChangeListener; import ch.ethz.dcg.jukefox.controller.player.IPlaybackInfoBroadcaster; import ch.ethz.dcg.jukefox.controller.player.IReadOnlyPlayerController; import ch.ethz.dcg.jukefox.model.AbstractCollectionModelManager; import ch.ethz.dcg.jukefox.model.AbstractPlayerModelManager; import ch.ethz.dcg.jukefox.model.collection.BaseAlbum; import ch.ethz.dcg.jukefox.model.collection.BaseArtist; import ch.ethz.dcg.jukefox.model.collection.BaseSong; import ch.ethz.dcg.jukefox.model.collection.IPlaylist; import ch.ethz.dcg.jukefox.model.collection.IReadOnlyPlaylist; import ch.ethz.dcg.jukefox.model.collection.Playlist; import ch.ethz.dcg.jukefox.model.collection.PlaylistSong; import ch.ethz.dcg.jukefox.model.commons.EmptyPlaylistException; import ch.ethz.dcg.jukefox.model.commons.PlaylistPositionOutOfRangeException; import ch.ethz.dcg.jukefox.model.player.PlayModeType; import ch.ethz.dcg.jukefox.playmode.ContextShuffleManager; import ch.ethz.dcg.jukefox.playmode.ContextShufflePlayMode; import ch.ethz.dcg.jukefox.playmode.IPlayMode; import ch.ethz.dcg.jukefox.playmode.MagicPlayMode; import ch.ethz.dcg.jukefox.playmode.PlayOncePlayMode; import ch.ethz.dcg.jukefox.playmode.RandomShufflePlayMode; import ch.ethz.dcg.jukefox.playmode.RepeatAllPlayMode; import ch.ethz.dcg.jukefox.playmode.RepeatSongPlayMode; import ch.ethz.dcg.jukefox.playmode.ShufflePlaylistPlayMode; import ch.ethz.dcg.jukefox.playmode.SimilarPlayMode; import ch.ethz.dcg.jukefox.playmode.SmartShuffleManager; import ch.ethz.dcg.jukefox.playmode.SmartShufflePlayMode; public class PlaylistManager implements IPlaylistManager { private static final String TAG = PlaylistManager.class.getSimpleName(); private IPlayMode currentPlayMode; private IPlaylist currentPlaylist = new Playlist(); protected AbstractCollectionModelManager collectionModel; protected AbstractPlayerModelManager playerModel; protected IPlaybackInfoBroadcaster listenerInformer; protected IReadOnlyPlayerController playerController; protected List<IOnPlaylistStateChangeListener> stateChangeListeners; public PlaylistManager(AbstractCollectionModelManager collectionModel, AbstractPlayerModelManager playerModel, IPlaybackInfoBroadcaster listenerInformer, IReadOnlyPlayerController playerController) { this.collectionModel = collectionModel; this.playerModel = playerModel; this.listenerInformer = listenerInformer; this.playerController = playerController; stateChangeListeners = new LinkedList<IOnPlaylistStateChangeListener>(); setPlayMode(PlayModeType.SMART_SHUFFLE, 0, Constants.SAME_SONG_AVOIDANCE_NUM); } @Override public void appendSongAtEnd(PlaylistSong<BaseArtist, BaseAlbum> song) { currentPlaylist.appendSongAtEnd(song); listenerInformer.informPlaylistChangeListener(getCurrentPlaylist()); } @Override public void appendSongsAtEnd(List<PlaylistSong<BaseArtist, BaseAlbum>> songs) { currentPlaylist.appendSongsAtEnd(songs); listenerInformer.informPlaylistChangeListener(getCurrentPlaylist()); } @Override public void clearPlaylist() { currentPlaylist = new Playlist(); listenerInformer.informPlaylistChangeListener(getCurrentPlaylist()); } @Override public void insertSongAtPosition(PlaylistSong<BaseArtist, BaseAlbum> song, int position) throws PlaylistPositionOutOfRangeException { currentPlaylist.insertSongAtPosition(song, position); listenerInformer.informPlaylistChangeListener(getCurrentPlaylist()); } @Override public void insertSongsAtPosition(List<PlaylistSong<BaseArtist, BaseAlbum>> songs, int position) throws PlaylistPositionOutOfRangeException { currentPlaylist.insertSongsAtPosition(songs, position); listenerInformer.informPlaylistChangeListener(getCurrentPlaylist()); } @Override public void insertSongAsNext(PlaylistSong<BaseArtist, BaseAlbum> song) { try { int position; try { position = getCurrentSongIndex() + 1; } catch (EmptyPlaylistException e) { position = 0; Log.w(TAG, e); } if (currentPlaylist.getSize() == 0) { position = 0; } else if (position >= currentPlaylist.getSize()) { position = currentPlaylist.getSize(); } currentPlaylist.insertSongAtPosition(song, position); } catch (PlaylistPositionOutOfRangeException e) { Log.w(TAG, e); } listenerInformer.informPlaylistChangeListener(currentPlaylist); } @Override public void insertSongsAsNext(List<PlaylistSong<BaseArtist, BaseAlbum>> songs) throws PlaylistPositionOutOfRangeException, EmptyPlaylistException { try { int position; try { position = getCurrentSongIndex() + 1; } catch (EmptyPlaylistException e) { position = 0; Log.w(TAG, e); } if (currentPlaylist.getSize() == 0) { position = 0; } else if (position >= currentPlaylist.getSize()) { position = currentPlaylist.getSize(); } currentPlaylist.insertSongsAtPosition(songs, position); } catch (PlaylistPositionOutOfRangeException e) { Log.w(TAG, e); } listenerInformer.informPlaylistChangeListener(getCurrentPlaylist()); } @Override public void moveSong(int oldPosition, int newPosition) throws EmptyPlaylistException, PlaylistPositionOutOfRangeException { currentPlaylist.moveSong(oldPosition, newPosition); listenerInformer.informPlaylistChangeListener(getCurrentPlaylist()); } @Override public void removeSongFromPlaylist(int position) throws EmptyPlaylistException, PlaylistPositionOutOfRangeException { currentPlaylist.removeSong(position); listenerInformer.informPlaylistChangeListener(getCurrentPlaylist()); } @Override public void setCurrentSongIndex(int index) throws PlaylistPositionOutOfRangeException { currentPlaylist.setPositionInList(index); try { // Log.v(TAG, "SongPosChanged " + index); listenerInformer.informCurrentSongChangeListener(getCurrentSong()); } catch (EmptyPlaylistException e) { Log.w(TAG, e); } } @Override public void setPlayMode(IPlayMode playMode) { if (playMode != null) { currentPlayMode = playMode; } } @Override public void setPlaylist(IPlaylist playlist) { if (playlist == null) { return; } currentPlaylist = playlist; applyPlaylistExtras(); listenerInformer.informPlaylistChangeListener(getCurrentPlaylist()); } private void applyPlaylistExtras() { if (currentPlaylist.hasExtras()) { // PlayModeType playMode = // PlayModeType.byValue(currentPlaylist.getPlayMode()); // setPlayMode(playMode); try { setCurrentSongIndex(currentPlaylist.getPositionInList()); } catch (PlaylistPositionOutOfRangeException e) { Log.w(TAG, e); } } } @Override public IReadOnlyPlaylist getCurrentPlaylist() { // Update position in Song to the current value currentPlaylist.setPositionInSong(playerController.getPlaybackPosition()); // Log.v(TAG, "Cur Pos in Song: " + currentPlaylist.getPositionInSong()); return currentPlaylist; } @Override public PlaylistSong<BaseArtist, BaseAlbum> getCurrentSong() throws EmptyPlaylistException { try { // Log.v(TAG, "Playlist size: " + currentPlaylist.getPlaylistSize()); return currentPlaylist.getSongAtPosition(getCurrentSongIndex()); } catch (PlaylistPositionOutOfRangeException e) { Log.w(TAG, e); throw new EmptyPlaylistException(); } } @Override public int getCurrentSongIndex() throws EmptyPlaylistException { if (currentPlaylist.isPlaylistEmpty()) { throw new EmptyPlaylistException(); } return currentPlaylist.getPositionInList(); } @Override public IPlayMode getPlayMode() { return currentPlayMode; } @Override public boolean isPlaylistEmptyOrAtEnd() { int size = currentPlaylist.getSongList().size(); try { return size == 0 || getCurrentSongIndex() >= size - 1; } catch (EmptyPlaylistException e) { return true; } } @Override public void setPlayMode(PlayModeType playModeType, int artistAvoidance, int songAvoidance) { IPlayMode playMode = null; SmartShuffleManager smartShuffleManager = null; // int artistAvoidance = 0; // TODO: read realSettings // int songAvoidance = 50; // TODO: read realSettings switch (playModeType) { case MAGIC: smartShuffleManager = new SmartShuffleManager(collectionModel, playerModel); playMode = new MagicPlayMode(collectionModel, playerModel, smartShuffleManager, playerController); break; case PLAY_ONCE: playMode = new PlayOncePlayMode(collectionModel, playerModel); break; case RANDOM_SHUFFLE: playMode = new RandomShufflePlayMode(collectionModel, playerModel, songAvoidance); break; case REPEAT: playMode = new RepeatAllPlayMode(collectionModel, playerModel); break; case REPEAT_SONG: playMode = new RepeatSongPlayMode(collectionModel, playerModel); break; case SHUFFLE_PLAYLIST: playMode = new ShufflePlaylistPlayMode(collectionModel, playerModel, songAvoidance); break; case SIMILAR: BaseSong<BaseArtist, BaseAlbum> seedSong = null; try { seedSong = getCurrentSong(); } catch (EmptyPlaylistException e) { e.printStackTrace(); } playMode = new SimilarPlayMode(collectionModel, playerModel, artistAvoidance, songAvoidance, seedSong); break; case SMART_SHUFFLE: smartShuffleManager = new SmartShuffleManager(collectionModel, playerModel); playMode = new SmartShufflePlayMode(collectionModel, playerModel, smartShuffleManager, playerController); break; case CONTEXT_SHUFFLE: songAvoidance = 0; // TODO: read realSettings ContextShuffleManager contextShuffleManager = new ContextShuffleManager(collectionModel, playerModel); playMode = new ContextShufflePlayMode(collectionModel, playerModel, contextShuffleManager, playerController); break; } setPlayMode(playMode); } @Override public void shufflePlaylist(int startPosition) { currentPlaylist.shuffle(startPosition); listenerInformer.informPlaylistChangeListener(getCurrentPlaylist()); } }