/**
  * Return ordered rarely listen albums list.
  *
  * @param bHideUnmounted if true, unmounted albums are not chosen
  * @param iNb nb of items to return
  * @return top albums, can be less items than required according to nb of available albums
  */
 public List<Album> getRarelyListenAlbums(boolean bHideUnmounted, int iNb) {
   // create a temporary table to remove unmounted albums
   // We consider an album as mounted if a least one track is mounted
   // This hashmap contains album-> album hits (each track hit average)
   final Map<Album, Float> cache =
       new HashMap<Album, Float>(AlbumManager.getInstance().getElementCount());
   // This hashmap contains album-> nb of tracks already taken into account
   // for average
   Map<Album, Integer> cacheNb =
       new HashMap<Album, Integer>(AlbumManager.getInstance().getElementCount());
   ReadOnlyIterator<Track> it = TrackManager.getInstance().getTracksIterator();
   while (it.hasNext()) {
     Track track = it.next();
     if (track.getPlayeableFile(bHideUnmounted) != null) {
       float newHits = 0f;
       Integer nb = cacheNb.get(track.getAlbum());
       if (nb == null) {
         nb = 0;
       }
       Float previousRate = cache.get(track.getAlbum());
       if (previousRate == null) {
         newHits = track.getHits();
       } else {
         newHits = ((previousRate * nb) + track.getHits()) / (nb + 1);
       }
       cacheNb.put(track.getAlbum(), nb + 1);
       cache.put(track.getAlbum(), newHits);
     }
   }
   // Now sort albums by rating
   List<Album> sortedAlbums = new ArrayList<Album>(cache.keySet());
   Collections.sort(
       sortedAlbums,
       new Comparator<Album>() {
         public int compare(Album o1, Album o2) {
           // We inverse comparison as we want lowest scores
           return (int) (cache.get(o2) - cache.get(o1));
         }
       });
   return getTopAlbums(sortedAlbums, iNb);
 }
 /**
  * Return newest albums
  *
  * @param bHideUnmounted if true, unmounted albums are not chosen
  * @param iNb nb of items to return
  * @return newest albums
  */
 public List<Album> getNewestAlbums(boolean bHideUnmounted, int iNb) {
   // create a temporary table to remove unmounted albums
   // We consider an album as mounted if a least one track is mounted
   // This hashmap contains album-> discovery date
   final HashMap<Album, Date> cache =
       new HashMap<Album, Date>(AlbumManager.getInstance().getElementCount());
   for (Track track : TrackManager.getInstance().getTracks()) {
     if (track.getPlayeableFile(bHideUnmounted) != null) {
       cache.put(track.getAlbum(), track.getAdditionDate());
     }
   }
   // Now sort albums by discovery date
   ArrayList<Album> sortedAlbums = new ArrayList<Album>(cache.keySet());
   Collections.sort(
       sortedAlbums,
       new Comparator<Album>() {
         public int compare(Album o1, Album o2) {
           return cache.get(o1).compareTo(cache.get(o2));
         }
       });
   return getTopAlbums(sortedAlbums, iNb);
 }
 /**
  * Return top albums based on the average of each album rating
  *
  * @param bHideUnmounted if true, unmounted albums are not chosen
  * @param iNbBestofAlbums nb of items to return
  * @return top albums, can be less items than required according to nb of available albums
  */
 public List<Album> getBestOfAlbums(boolean bHideUnmounted, int iNbBestofAlbums) {
   // create a temporary table to remove unmounted albums
   // We consider an album as mounted if a least one track is mounted
   // This hashmap contains album-> album rates
   final HashMap<Album, Float> cacheRate =
       new HashMap<Album, Float>(AlbumManager.getInstance().getElementCount());
   // This hashmap contains album-> nb of tracks already taken into account
   // for average
   HashMap<Album, Integer> cacheNb =
       new HashMap<Album, Integer>(AlbumManager.getInstance().getElementCount());
   for (Track track : TrackManager.getInstance().getTracks()) {
     if (track.getPlayeableFile(bHideUnmounted) != null) {
       float newRate = 0f;
       Integer nb = cacheNb.get(track.getAlbum());
       if (nb == null) {
         nb = 0;
       }
       Float previousRate = cacheRate.get(track.getAlbum());
       if (previousRate == null) {
         newRate = track.getRate();
       } else {
         newRate = ((previousRate * nb) + track.getRate()) / (nb + 1);
       }
       cacheNb.put(track.getAlbum(), nb + 1);
       cacheRate.put(track.getAlbum(), newRate);
     }
   }
   // Now sort albums by rating
   ArrayList<Album> sortedAlbums = new ArrayList<Album>(cacheRate.keySet());
   Collections.sort(
       sortedAlbums,
       new Comparator<Album>() {
         public int compare(Album o1, Album o2) {
           // lowest first
           return (int) (cacheRate.get(o1) - cacheRate.get(o2));
         }
       });
   return getTopAlbums(sortedAlbums, iNbBestofAlbums);
 }
 /**
  * Force to refresh the album max rating, it is not done soon as it is pretty CPU consumming and
  * we don't need a track by track rating precision
  */
 public void refreshMaxRating() {
   // create a temporary table to remove unmounted albums
   // We consider an album as mounted if a least one track is mounted
   // This hashmap contains album-> album rates
   final HashMap<Album, Float> cacheRate =
       new HashMap<Album, Float>(AlbumManager.getInstance().getElementCount());
   // This hashmap contains album-> nb of tracks already taken into account
   // for average
   HashMap<Album, Integer> cacheNb =
       new HashMap<Album, Integer>(AlbumManager.getInstance().getElementCount());
   for (Track track : TrackManager.getInstance().getTracks()) {
     if (track.getPlayeableFile(ConfigurationManager.getBoolean(CONF_OPTIONS_HIDE_UNMOUNTED))
         != null) {
       float newRate = 0f;
       Integer nb = cacheNb.get(track.getAlbum());
       if (nb == null) {
         nb = 0;
       }
       Float previousRate = cacheRate.get(track.getAlbum());
       if (previousRate == null) {
         newRate = track.getRate();
       } else {
         newRate = ((previousRate * nb) + track.getRate()) / (nb + 1);
       }
       cacheNb.put(track.getAlbum(), nb + 1);
       cacheRate.put(track.getAlbum(), newRate);
     }
   }
   // OK, now keep only the highest score
   for (Album album : cacheRate.keySet()) {
     long value = Math.round(cacheRate.get(album));
     if (value > maxRate) {
       maxRate = value;
     }
   }
 }