001package org.intellimate.izou.sdk.frameworks.music.player; 002 003import org.intellimate.izou.resource.ResourceModel; 004 005import java.util.Arrays; 006import java.util.HashMap; 007import java.util.Optional; 008import java.util.function.BiPredicate; 009 010/** 011 * This class represents the Information about one track, this class is immutable 012 * @author LeanderK 013 * @version 1.0 014 */ 015@SuppressWarnings("unused") 016public class TrackInfo { 017 public static final String nameDescriptor = "izou.music.trackinfo.name"; 018 private final String name; 019 public static final String artistDescriptor = "izou.music.trackinfo.artist"; 020 private final String artist; 021 public static final String albumDescriptor = "izou.music.trackinfo.album"; 022 private final String album; 023 public static final String albumCoverDescriptor = "izou.music.trackinfo.albumCover"; 024 private final byte[] albumCover; 025 public static final String albumCoverFormatDescriptor = "izou.music.trackinfo.albumCoverFormat"; 026 private final String albumCoverFormat; 027 public static final String dataDescriptor = "izou.music.trackinfo.data"; 028 private final String data; 029 public static final String yearDescriptor = "izou.music.trackinfo.year"; 030 private final String year; 031 public static final String genreDescriptor = "izou.music.trackinfo.genre"; 032 private final String genre; 033 public static final String bmpDescriptor = "izou.music.trackinfo.bmp"; 034 private final String bmp; 035 public static final String durationDescriptor = "izou.music.trackinfo.duration"; 036 private final long duration; 037 038 public TrackInfo(String name) { 039 this.name = name; 040 this.artist = null; 041 this.album = null; 042 albumCover = null; 043 albumCoverFormat = null; 044 data = null; 045 year = null; 046 genre = null; 047 bmp = null; 048 duration = -1; 049 } 050 051 public TrackInfo(String name, String artist, String album) { 052 this.name = name; 053 this.artist = artist; 054 this.album = album; 055 albumCover = null; 056 albumCoverFormat = null; 057 data = null; 058 year = null; 059 genre = null; 060 bmp = null; 061 duration = -1; 062 } 063 064 public TrackInfo(String name, String artist, String album, byte[] albumCover, String albumCoverFormat) { 065 this.name = name; 066 this.artist = artist; 067 this.album = album; 068 this.albumCover = albumCover; 069 this.albumCoverFormat = albumCoverFormat; 070 data = null; 071 year = null; 072 genre = null; 073 bmp = null; 074 duration = -1; 075 } 076 077 public TrackInfo(String name, String artist, String album, byte[] albumCover, String albumCoverFormat, String data) { 078 this.name = name; 079 this.artist = artist; 080 this.album = album; 081 this.albumCover = albumCover; 082 this.albumCoverFormat = albumCoverFormat; 083 this.data = data; 084 year = null; 085 genre = null; 086 bmp = null; 087 duration = -1; 088 } 089 090 public TrackInfo(String name, String artist, String album, byte[] albumCover, String albumCoverFormat, String data, String year, String genre, String bmp, long duration) { 091 this.name = name; 092 this.artist = artist; 093 this.album = album; 094 this.albumCover = albumCover; 095 this.albumCoverFormat = albumCoverFormat; 096 this.data = data; 097 this.year = year; 098 this.genre = genre; 099 this.bmp = bmp; 100 this.duration = duration; 101 } 102 103 /** 104 * returns a String containing the Name of the Track 105 * @return the optional Name 106 */ 107 public Optional<String> getName() { 108 return getOptionalOrEmtpyIfNull(name); 109 } 110 111 /** 112 * returns a String containing the Name of the Artist 113 * @return the optional Artist 114 */ 115 public Optional<String> getArtist() { 116 return getOptionalOrEmtpyIfNull(artist); 117 } 118 119 /** 120 * returns a String containing the Name of the Album 121 * @return the optional Artist 122 */ 123 public Optional<String> getAlbum() { 124 return getOptionalOrEmtpyIfNull(album); 125 } 126 127 /** 128 * returns the album cover as bytes, format specified by: {@link #getAlbumCoverFormat()}. 129 * @return the optional Album Cover 130 */ 131 public Optional<byte[]> getAlbumCover() { 132 return getOptionalOrEmtpyIfNull(albumCover); 133 } 134 135 /** 136 * returns the format of the album cover, which can be obtained by calling {@link #getAlbumCover()}. 137 * @return the optional Format 138 */ 139 public Optional<String> getAlbumCoverFormat() { 140 return getOptionalOrEmtpyIfNull(albumCoverFormat); 141 } 142 143 /** 144 * returns the data of the TrackInfo. 145 * <p> 146 * this field is mostly internal, can be an url etc. should be used only if obtained from a player 147 * </p> 148 * @return the optional data 149 */ 150 public Optional<String> getData() { 151 return getOptionalOrEmtpyIfNull(data); 152 } 153 154 /** 155 * returns a String containing the Year of the release 156 * @return the optional Year of the release 157 */ 158 public Optional<String> getYear() { 159 return getOptionalOrEmtpyIfNull(year); 160 } 161 162 /** 163 * returns a String containing the Genre 164 * @return the optional Genre 165 */ 166 public Optional<String> getGenre() { 167 return getOptionalOrEmtpyIfNull(genre); 168 } 169 170 /** 171 * returns a String containing the BMP 172 * @return the optional BMP 173 */ 174 public Optional<String> getBmp() { 175 return getOptionalOrEmtpyIfNull(bmp); 176 } 177 178 /** 179 * returns a long containing the Duration in milliseconds 180 * @return the optional Duration 181 */ 182 public Optional<Long> getDuration() { 183 if (duration < 0) { 184 return Optional.empty(); 185 } else { 186 return Optional.of(duration); 187 } 188 } 189 190 private <T> Optional<T> getOptionalOrEmtpyIfNull(T t) { 191 if (t == null) { 192 return Optional.empty(); 193 } else { 194 return Optional.of(t); 195 } 196 } 197 198 /** 199 * retruns true if any of these arguments is already existing and would be overwritten, otherwise retruns false. 200 * The method also returns true if everything is null except the albumCover-Format (maybe known in advance). 201 * @param trackInfo the trackInfo to compare against 202 * @return true if new 203 */ 204 public boolean isNew(TrackInfo trackInfo) { 205 return isNew(trackInfo.name, 206 trackInfo.artist, 207 trackInfo.album, 208 trackInfo.albumCover, 209 trackInfo.albumCoverFormat, 210 trackInfo.data, 211 trackInfo.year, 212 trackInfo.genre, 213 trackInfo.bmp, 214 trackInfo.duration); 215 } 216 217 /** 218 * retruns true if any of these arguments is already existing and would be overwritten, otherwise retruns false. 219 * The method also returns true if everything is null except the albumCover-Format (maybe known in advance). 220 * @param name the name 221 * @param artist the artist 222 * @param album the album 223 * @param albumCover the album cover 224 * @param albumCoverFormat the album cover format 225 * @param id the id of the track 226 * @param year the year 227 * @param genre the genre 228 * @param duration the duration 229 * @param bmp the bmp 230 * @return true if new 231 */ 232 public boolean isNew(String name, String artist, String album, byte[] albumCover, String albumCoverFormat, String id, String year, String genre, String bmp, long duration) { 233 if (name == null && artist == null && album == null && albumCover == null && id == null) 234 return true; 235 BiPredicate<String, String> compareStrings = (newString, oldString) -> 236 oldString != null && newString != null && !oldString.equals(newString); 237 if (compareStrings.test(name, this.name)) { 238 return true; 239 } 240 if (compareStrings.test(artist, this.artist)) { 241 return true; 242 } 243 if (compareStrings.test(album, this.album)) { 244 return true; 245 } 246 if (compareStrings.test(id, this.data)) { 247 return true; 248 } 249 if (compareStrings.test(albumCoverFormat, this.albumCoverFormat)) { 250 return true; 251 } 252 if (compareStrings.test(year, this.year)) { 253 return true; 254 } 255 if (compareStrings.test(genre, this.genre)) { 256 return true; 257 } 258 if (this.duration > 0 && duration > 0 && this.duration == duration) { 259 return true; 260 } 261 if (compareStrings.test(bmp, this.bmp)) { 262 return true; 263 } 264 if (albumCover != null) { 265 if (this.albumCover == null || !Arrays.equals(albumCover, this.albumCover)) 266 return true; 267 } 268 return false; 269 } 270 271 /** 272 * returns a trackinfo if some information was added and not overwritten 273 * @param trackInfo the data to compare 274 * @return a trackinfo if some information was updated 275 */ 276 public Optional<TrackInfo> update(TrackInfo trackInfo) { 277 return update(trackInfo.name, 278 trackInfo.artist, 279 trackInfo.album, 280 trackInfo.albumCover, 281 trackInfo.albumCoverFormat, 282 trackInfo.data, 283 trackInfo.year, 284 trackInfo.genre, 285 trackInfo.bmp, 286 trackInfo.duration); 287 } 288 289 /** 290 * returns a trackinfo if some information was added and not overwritten (see isNew) AND a change occurred. 291 * @param name the name 292 * @param artist the artist 293 * @param album the album 294 * @param albumCover the album cover 295 * @param coverFormat the album cover format 296 * @param data the data 297 * @param year the year 298 * @param genre the genre 299 * @param duration the duration 300 * @param bmp the bmp 301 * @return a trackInfo if some information was updated, and an empty optional if: 1. information would be ovewritten 302 * or 2. no change occured 303 */ 304 public Optional<TrackInfo> update(String name, String artist, String album, byte[] albumCover, String coverFormat, String data, String year, String genre, String bmp, long duration) { 305 if (isNew(name, artist, album, albumCover, albumCoverFormat, data, year, genre, bmp, duration)) 306 return Optional.empty(); 307 boolean change = false; 308 if (name != null && !name.equals(this.name)) { 309 change = true; 310 } 311 if (artist != null && !artist.equals(this.artist)) { 312 change = true; 313 } 314 if (album != null && !album.equals(this.album)) { 315 change = true; 316 } 317 if (name != null && !name.equals(this.name)) { 318 change = true; 319 } 320 if (albumCoverFormat != null && !albumCoverFormat.equals(this.albumCoverFormat)) { 321 change = true; 322 } 323 if (data != null && !data.equals(this.data)) { 324 change = true; 325 } 326 if (year != null && !year.equals(this.year)) { 327 change = true; 328 } 329 if (genre != null && !genre.equals(this.genre)) { 330 change = true; 331 } 332 if (duration > 0 && duration != this.duration) { 333 change = true; 334 } 335 if (bmp != null && !bmp.equals(this.bmp)) { 336 change = true; 337 } 338 if (!change) 339 return Optional.empty(); 340 return Optional.of(new TrackInfo( 341 this.name == null? name : this.name, 342 this.artist == null? artist : this.artist, 343 this.album == null? album : this.album, 344 this.albumCover == null? albumCover : this.albumCover, 345 this.albumCoverFormat == null? albumCoverFormat : this.albumCoverFormat, 346 this.data == null? data : this.data, 347 this.year == null? year : this.year, 348 this.genre == null? genre : this.genre, 349 this.bmp == null? bmp : this.bmp, 350 this.duration < 0 ? duration : this.duration 351 )); 352 } 353 354 /** 355 * exports the TrackInfo to a Hashmap 356 * @return a HashMap 357 */ 358 public HashMap<String, Object> export() { 359 HashMap<String, Object> data = new HashMap<>(); 360 data.put(nameDescriptor, name); 361 data.put(artistDescriptor, artist); 362 data.put(albumDescriptor, albumDescriptor); 363 data.put(albumCoverDescriptor, albumCover); 364 data.put(albumCoverFormatDescriptor, albumCoverFormatDescriptor); 365 data.put(dataDescriptor, this.data); 366 data.put(yearDescriptor, this.year); 367 data.put(genreDescriptor, this.genre); 368 data.put(durationDescriptor, this.duration); 369 data.put(bmpDescriptor, this.bmp); 370 return data; 371 } 372 373 /** 374 * returns the optional TrackInfo if the HashMap contains no malformed data 375 * @param hashMap the data to import from 376 * @return an optional 377 */ 378 public static Optional<TrackInfo> importFromHashMap(HashMap<String, Object> hashMap) { 379 try { 380 String name = (String) hashMap.get(nameDescriptor); 381 String album = (String) hashMap.get(albumDescriptor); 382 String artist = (String) hashMap.get(artistDescriptor); 383 byte[] albumCover = (byte[]) hashMap.get(albumCoverDescriptor); 384 String albumCoverFormat = (String) hashMap.get(albumCoverFormatDescriptor); 385 String data = (String) hashMap.get(dataDescriptor); 386 String year = (String) hashMap.get(yearDescriptor); 387 String genre = (String) hashMap.get(genreDescriptor); 388 long duration = (Long) hashMap.get(durationDescriptor); 389 String bmp = (String) hashMap.get(bmpDescriptor); 390 return Optional.of(new TrackInfo(name, artist, album, albumCover, albumCoverFormat, data, year, genre, bmp, duration)); 391 } catch (ClassCastException e) { 392 return Optional.empty(); 393 } 394 } 395 396 /** 397 * creates a TrackInfo from the resourceModel 398 * @param resourceModel the resourceModel 399 * @return the optional TrackInfo 400 */ 401 public static Optional<TrackInfo> importFromResource(ResourceModel resourceModel) { 402 Object resource = resourceModel.getResource(); 403 try { 404 @SuppressWarnings("unchecked") 405 HashMap<String, Object> hashMap = (HashMap<String, Object>) resource; 406 return importFromHashMap(hashMap); 407 } catch (ClassCastException e) { 408 return Optional.empty(); 409 } 410 } 411 412 @Override 413 public boolean equals(Object o) { 414 if (this == o) return true; 415 if (!(o instanceof TrackInfo)) return false; 416 417 TrackInfo trackInfo = (TrackInfo) o; 418 419 if (name != null ? !name.equals(trackInfo.name) : trackInfo.name != null) return false; 420 if (artist != null ? !artist.equals(trackInfo.artist) : trackInfo.artist != null) return false; 421 if (album != null ? !album.equals(trackInfo.album) : trackInfo.album != null) return false; 422 if (year != null ? !year.equals(trackInfo.year) : trackInfo.year != null) return false; 423 if (genre != null ? !genre.equals(trackInfo.genre) : trackInfo.genre != null) return false; 424 if (bmp != null ? !bmp.equals(trackInfo.bmp) : trackInfo.bmp != null) return false; 425 return !(duration > 0l ? duration != trackInfo.duration : trackInfo.duration < 0); 426 427 } 428 429 @Override 430 public int hashCode() { 431 int result = name != null ? name.hashCode() : 0; 432 result = 31 * result + (artist != null ? artist.hashCode() : 0); 433 result = 31 * result + (album != null ? album.hashCode() : 0); 434 result = 31 * result + (year != null ? year.hashCode() : 0); 435 result = 31 * result + (genre != null ? genre.hashCode() : 0); 436 result = 31 * result + (bmp != null ? bmp.hashCode() : 0); 437 result = (int) (31 * result + (duration > 0 ? duration : 0)); 438 return result; 439 } 440}