001package org.intellimate.izou.sdk.frameworks.music.player.template; 002 003import org.intellimate.izou.events.EventModel; 004import org.intellimate.izou.resource.ResourceModel; 005import org.intellimate.izou.sdk.frameworks.music.Capabilities; 006import org.intellimate.izou.sdk.frameworks.music.events.PlayerError; 007import org.intellimate.izou.sdk.frameworks.music.player.*; 008import org.intellimate.izou.sdk.frameworks.music.resources.CommandResource; 009import org.intellimate.izou.sdk.frameworks.music.resources.ProgressResource; 010import org.intellimate.izou.sdk.frameworks.music.resources.TrackInfoResource; 011import org.intellimate.izou.sdk.frameworks.music.resources.VolumeResource; 012 013import java.util.List; 014import java.util.Objects; 015import java.util.Optional; 016import java.util.function.Consumer; 017import java.util.function.Function; 018import java.util.function.Supplier; 019import java.util.stream.Collectors; 020 021/** 022 * this class is used to handle the Commands and directs them to the registered methods. 023 * @author LeanderK 024 * @version 1.0 025 */ 026public class CommandHandler { 027 private final MusicHelper musicHelper; 028 private final MusicProvider musicProvider; 029 private final Capabilities capabilities; 030 private final Runnable stopCallback; 031 private Consumer<String> playPause = null; 032 private Consumer<TrackInfo> selectTrack = null; 033 private Consumer<String> nextPrevious = null; 034 private Consumer<Progress> jumpProgress = null; 035 private Consumer<String> changePlayback = null; 036 private Consumer<Volume> changeVolume; 037 private Function<String, Playlist> playlistForNameFunction = null; 038 private Supplier<List<String>> availablePlaylist = null; 039 040 /** 041 * creates a new CommandHandler 042 * @param musicHelper the musicHelper 043 * @param musicProvider the musicProvider 044 * @param stopCallback the callback for the stop-command 045 * @param capabilities the capabilities 046 */ 047 public CommandHandler(MusicHelper musicHelper, MusicProvider musicProvider, 048 Runnable stopCallback, Capabilities capabilities) { 049 this.musicHelper = musicHelper; 050 this.capabilities = capabilities; 051 this.musicProvider = musicProvider; 052 this.stopCallback = stopCallback; 053 } 054 055 /** 056 * adds the ability for the Play/Pause requests 057 * @param controller the controller for callback 058 */ 059 public void setPlayPauseController(Consumer<String> controller) { 060 if (controller == null) 061 return; 062 this.playPause = controller; 063 capabilities.setPlayPauseControl(true); 064 } 065 066 /** 067 * adds the ability to select tracks 068 * @param controller the controller for callback 069 */ 070 public void setTrackSelectorController(Consumer<TrackInfo> controller) { 071 if (controller == null) 072 return; 073 selectTrack = controller; 074 capabilities.setAbleToSelectTrack(true); 075 } 076 077 /** 078 * adds the ability to select the next/previous track 079 * @param controller the controller for callback 080 */ 081 public void setNextPreviousController(Consumer<String> controller) { 082 if (controller == null) 083 return; 084 nextPrevious = controller; 085 capabilities.setNextPrevious(true); 086 } 087 088 /** 089 * adds the ability to jump to a specified position of the current track 090 * @param controller the controller for callback 091 */ 092 public void setJumpProgressController(Consumer<Progress> controller) { 093 if (controller == null) 094 return; 095 jumpProgress = controller; 096 capabilities.setAbleToJump(true); 097 } 098 099 /** 100 * adds the ability to change the playback 101 * @param controller the controller for callback 102 */ 103 public void setPlaybackChangeableController(Consumer<String> controller) { 104 if (controller == null) 105 return; 106 changePlayback = controller; 107 capabilities.setPlaybackChangeable(true); 108 } 109 110 /** 111 * adds the ability to change the volume from outside the player 112 * @param controller the controller for callback 113 */ 114 public void setVolumeChangeableController(Consumer<Volume> controller) { 115 if (controller == null) 116 return; 117 changeVolume = controller; 118 capabilities.setChangeVolume(true); 119 } 120 121 /** 122 * adds the ability to return the available playlists on request. 123 * @param availablePlaylist retruns a List of Strings which represent the Playlists 124 * @param playlistForNameFunction takes a String from the List and returns the Playlist 125 */ 126 public void broadcastAvailablePlaylists(Supplier<List<String>> availablePlaylist, Function<String, Playlist> playlistForNameFunction) { 127 if (availablePlaylist == null || playlistForNameFunction == null) 128 return; 129 this.availablePlaylist = availablePlaylist; 130 this.playlistForNameFunction = playlistForNameFunction; 131 capabilities.setBroadcasting(true); 132 } 133 134 /** 135 * this method gets called when a new Command was found. It automatically fires the update Event or an error 136 * @param eventModel the event with the Commands 137 */ 138 public void handleCommandResources(EventModel eventModel) { 139 List<ResourceModel<String>> resourceModels = eventModel.getListResourceContainer() 140 .provideResource(CommandResource.ResourceID) 141 .stream() 142 .filter(resourceModel -> resourceModel.getResource() instanceof String) 143 .map(resourceModel -> { 144 try { 145 //noinspection unchecked 146 return (ResourceModel<String>) resourceModel; 147 } catch (ClassCastException e) { 148 return null; 149 } 150 }) 151 .filter(Objects::nonNull) 152 .collect(Collectors.toList()); 153 for (ResourceModel<String> resourceModel : resourceModels) { 154 if (!CommandResource.verifyCommand(resourceModel.getResource())) 155 continue; 156 if (!CommandResource.verifyCapabilities(resourceModel.getResource(), capabilities)) { 157 musicHelper.playerError(PlayerError.ERROR_NOT_ABLE + "command: " + resourceModel.getResource(), 158 resourceModel.getProvider()); 159 continue; 160 } 161 switch (resourceModel.getResource()) { 162 case CommandResource.PLAY: if (!musicProvider.isPlaying()) 163 playPause.accept(resourceModel.getResource()); 164 break; 165 case CommandResource.PAUSE: if (musicProvider.isPlaying()) 166 playPause.accept(resourceModel.getResource()); 167 break; 168 case CommandResource.SELECT_TRACK: handleSelectTrack(eventModel, resourceModel); 169 break; 170 case CommandResource.NEXT: nextPrevious.accept(resourceModel.getResource()); 171 break; 172 case CommandResource.PREVIOUS: nextPrevious.accept(resourceModel.getResource()); 173 break; 174 case CommandResource.JUMP: handleJump(eventModel, resourceModel); 175 break; 176 case CommandResource.CHANGE_PLAYBACK: changePlayback.accept(resourceModel.getResource()); 177 break; 178 case CommandResource.CHANGE_VOLUME: handleVolume(eventModel, resourceModel); 179 break; 180 case CommandResource.STOP: stopCallback.run(); 181 break; 182 } 183 } 184 } 185 186 /** 187 * handles the volume-command 188 * @param eventModel the event 189 * @param resourceModel the resourcemodel 190 */ 191 private void handleVolume(EventModel eventModel, ResourceModel<String> resourceModel) { 192 Optional<Volume> volumeResource = VolumeResource.getVolume(eventModel); 193 if (!volumeResource.isPresent()) { 194 musicHelper.playerError(PlayerError.ERROR_ILLEGAL + "command: " + resourceModel.getResource() + "missing resource", 195 resourceModel.getProvider()); 196 } 197 changeVolume.accept(volumeResource.get()); 198 } 199 200 /** 201 * handles the jump-command 202 * @param eventModel the event 203 * @param resourceModel the resourcemodel 204 */ 205 private void handleJump(EventModel eventModel, ResourceModel<String> resourceModel) { 206 Optional<Progress> progress = ProgressResource.getProgress(eventModel); 207 if (!progress.isPresent()) { 208 musicHelper.playerError(PlayerError.ERROR_ILLEGAL + "command: " + resourceModel.getResource() + "missing resource", 209 resourceModel.getProvider()); 210 } 211 jumpProgress.accept(progress.get()); 212 } 213 214 /** 215 * handles the select Track command 216 * @param eventModel the event 217 * @param resourceModel the resource 218 */ 219 private void handleSelectTrack(EventModel eventModel, ResourceModel<String> resourceModel) { 220 Optional<TrackInfo> trackInfo = TrackInfoResource.getTrackInfo(eventModel); 221 if (!trackInfo.isPresent()) { 222 musicHelper.playerError(PlayerError.ERROR_ILLEGAL + "command: " + resourceModel.getResource() + "missing resource", 223 resourceModel.getProvider()); 224 } 225 selectTrack.accept(trackInfo.get()); 226 } 227 228 /** 229 * retruns the playlist for the specified name 230 * @param name the name of the playlist 231 * @return the playlist 232 */ 233 Playlist getPlaylistFromName(String name) { 234 return playlistForNameFunction.apply(name); 235 } 236 237 /** 238 * generates all available playlists. 239 * @return a list containing the names of all available Playlists. 240 */ 241 List<String> getAvailablePlaylists() { 242 return availablePlaylist.get(); 243 } 244}