/** Refresh last fm collection tabs. */
  private void refreshLastFMCollectionTabs() {
    String newArtist = null;
    File current = QueueModel.getPlayingFile();
    if (current != null) {
      newArtist = current.getTrack().getArtist().getName2();
    }
    // if none track playing
    if (current == null
        // Last.FM infos is disable
        || !Conf.getBoolean(Const.CONF_LASTFM_INFO)
        // None internet access option is set
        || Conf.getBoolean(Const.CONF_NETWORK_NONE_INTERNET_ACCESS)
        // If unknown artist
        || (newArtist == null || newArtist.equals(Messages.getString(UNKNOWN_ARTIST)))) {
      // Set empty panels
      SwingUtilities.invokeLater(
          new Runnable() {
            @Override
            public void run() {
              stopAllBusyLabels();
              tabs.setComponentAt(3, new JLabel(Messages.getString("SuggestionView.7")));
              tabs.setComponentAt(4, new JLabel(Messages.getString("SuggestionView.7")));
            }
          });
      return;
    }
    // Check if artist changed, otherwise, just leave
    if (newArtist.equals(this.artist)) {
      return;
    }
    // Save current artist
    artist = newArtist;
    // Display a busy panel in the mean-time
    SwingUtilities.invokeLater(
        new Runnable() {
          @Override
          public void run() {
            JXBusyLabel busy1 = new JXBusyLabel();
            busy1.setBusy(true);
            JXBusyLabel busy2 = new JXBusyLabel();
            busy2.setBusy(true);
            // stop all existing busy labels before we add the new ones...
            stopAllBusyLabels();
            tabs.setComponentAt(3, UtilGUI.getCentredPanel(busy1));
            tabs.setComponentAt(4, UtilGUI.getCentredPanel(busy2));
          }
        });
    // Use a swing worker as construct takes a lot of time
    SwingWorker<Void, Void> sw =
        new SwingWorker<Void, Void>() {
          JScrollPane jsp1;
          JScrollPane jsp2;

          @Override
          public Void doInBackground() {
            try {
              // Fetch last.fm calls and downloads covers
              preFetchOthersAlbum();
              preFetchSimilarArtists();
            } catch (Exception e) {
              Log.error(e);
            }
            return null;
          }

          @Override
          public void done() {
            jsp1 = getLastFMSuggestionsPanel(SuggestionType.OTHERS_ALBUMS, false);
            jsp2 = getLastFMSuggestionsPanel(SuggestionType.SIMILAR_ARTISTS, false);
            stopAllBusyLabels();
            tabs.setComponentAt(3, (jsp1 == null) ? new JPanel() : jsp1);
            tabs.setComponentAt(4, (jsp2 == null) ? new JPanel() : jsp2);
          }
        };
    sw.execute();
  }
  /* (non-Javadoc)
   * @see org.jajuk.services.dj.DigitalDJ#generatePlaylist()
   */
  @Override
  public List<File> generatePlaylist() {
    List<File> out = new ArrayList<File>(500);

    // get a global shuffle selection
    List<File> global = FileManager.getInstance().getGlobalShufflePlaylist();
    // Select by rate if needed
    filterFilesByRate(global);
    // None element, leave
    if (global.size() == 0) {
      return out;
    }
    // Build a ambience -> files map
    Map<Ambience, List<File>> hmAmbienceFiles = getAmbienceFilesList(global);
    // compute number of items to add
    int items = Math.min(global.size(), Const.NB_TRACKS_ON_ACTION);
    if (!bUnicity && items < Const.MIN_TRACKS_NUMBER_WITHOUT_UNICITY) {
      // under a limit, if collection is too small and no unicity, use
      // several times the same files
      items = Const.MIN_TRACKS_NUMBER_WITHOUT_UNICITY;
    }

    // Get first track
    for (File file : global) {
      if (transitions.get(0).getFrom().getGenres().contains(file.getTrack().getGenre())) {
        out.add(file);
        // Unicity in selection, remove it from this ambience
        if (bUnicity) {
          List<File> files = hmAmbienceFiles.get(getAmbience(file.getTrack().getGenre()));
          files.remove(file);
        }
        items--;
        break;
      }
    }
    // none matching track? return
    if (out.size() == 0) {
      return out;
    }

    // initialize current ambience with first track ambience (can be null for
    // unsorted tracks)
    Ambience currentAmbience = getAmbience(out.get(0).getTrack().getGenre());
    // start transition applying
    while (items > 0) {
      // A genre can be in only one transition
      Transition currentTransition = getTransition(currentAmbience);
      List<File> files = hmAmbienceFiles.get(currentAmbience);
      int nbTracks = 2;
      if (currentTransition != null) {
        nbTracks = currentTransition.getNbTracks();
      }
      // We remove one item as it has already been added through the first track
      if (out.size() == 1) {
        nbTracks--;
      }
      if (files != null && files.size() >= nbTracks) {
        for (int i = 0; i < nbTracks && files.size() > 0; i++) {
          File file = (File) UtilFeatures.getShuffleItem(files);
          out.add(file);
          items--;
          // Unicity in selection, remove it from this ambience
          if (bUnicity) {
            files.remove(file);
          }
        }
      } else { // no more tracks for this ambience ? leave
        // finally ensure that we don't select more than the max number of tracks
        filterFilesByMaxTrack(out);

        return out;
      }
      if (currentTransition != null) {
        currentAmbience = currentTransition.getTo();
      } else {
        break;
      }
    }

    // finally ensure that we don't select more than the max number of tracks
    filterFilesByMaxTrack(out);

    return out;
  }