/**
  * Test device accessibility.
  *
  * @return true if the device is available
  */
 public boolean test() {
   UtilGUI.waiting(); // waiting cursor
   boolean bOK = false;
   boolean bWasMounted = bMounted; // store mounted state of device before
   // mount test
   try {
     if (!bMounted) {
       mount(true);
     }
   } catch (final Exception e) {
     UtilGUI.stopWaiting();
     return false;
   }
   if (getLongValue(Const.XML_TYPE) != 5) { // not a remote device
     final File file = new File(sUrl);
     if (file.exists() && file.canRead()) { // see if the url exists
       // and is readable
       // check if this device was void
       boolean bVoid = true;
       for (org.jajuk.base.File f : FileManager.getInstance().getFiles()) {
         if (f.getDirectory().getDevice().equals(this)) {
           // at least one field in this device
           bVoid = false;
           break;
         }
       }
       if (!bVoid) { // if the device is not supposed to be void,
         // check if it is the case, if no, the device
         // must not be unix-mounted
         if (file.list().length > 0) {
           bOK = true;
         }
       } else { // device is void, OK we assume it is accessible
         bOK = true;
       }
     }
   } else {
     bOK = false; // TBI
   }
   // unmount the device if it was mounted only for the test
   if (!bWasMounted) {
     try {
       unmount(false, false);
     } catch (final Exception e1) {
       Log.error(e1);
     }
   }
   UtilGUI.stopWaiting();
   return bOK;
 }
 /* (non-Javadoc)
  * @see org.jdesktop.swingx.decorator.HighlightPredicate#isHighlighted(java.awt.Component, org.jdesktop.swingx.decorator.ComponentAdapter)
  */
 public boolean isHighlighted(Component renderer, ComponentAdapter adapter) {
   if (QueueModel.isStopped()) {
     return false;
   }
   Item item = model.getItemAt(adapter.row);
   if (item instanceof File && QueueModel.getPlayingFile() != null) {
     File file = (File) item;
     if (file.equals(QueueModel.getPlayingFile())) {
       return true;
     }
   } else if (item instanceof Track) {
     List<File> files = ((Track) item).getFiles();
     if (files.contains(QueueModel.getPlayingFile())) {
       return true;
     }
   }
   return false;
 }
 /**
  * Sets the url.
  *
  * @param url The sUrl to set.
  */
 public void setUrl(final String url) {
   sUrl = url;
   setProperty(Const.XML_URL, url);
   fio = new File(url);
   /** Reset files */
   for (final org.jajuk.base.File file : FileManager.getInstance().getFiles()) {
     file.reset();
   }
   /** Reset playlists */
   for (final Playlist plf : PlaylistManager.getInstance().getPlaylists()) {
     plf.reset();
   }
   /** Reset directories */
   for (final Directory dir : DirectoryManager.getInstance().getDirectories()) {
     dir.reset();
   }
   // Reset the root dir
   rootDir = null;
 }
 /**
  * Walk through tall Files and remove the ones for the current device.
  *
  * @param dirsToRefresh list of the directory to refresh, null if all of them
  * @return true if there was any file removed.
  */
 private boolean cleanFiles(List<Directory> dirsToRefresh) {
   boolean bChanges = false;
   final List<org.jajuk.base.File> files = FileManager.getInstance().getFiles();
   for (final org.jajuk.base.File file : files) {
     // check if it is a file located inside refreshed directory
     if (dirsToRefresh != null) {
       boolean checkIt = false;
       for (Directory directory : dirsToRefresh) {
         if (file.hasAncestor(directory)) {
           checkIt = true;
         }
       }
       // This item is not in given directories, just continue
       if (!checkIt) {
         continue;
       }
     }
     if (!ExitService.isExiting()
         && file.getDirectory().getDevice().equals(this)
         && file.isReady()
         &&
         // Remove file if it doesn't exist any more or if it is a iTunes
         // file (useful for jajuk < 1.4)
         (!file.getFIO().exists() || file.getName().startsWith("._"))) {
       FileManager.getInstance().removeFile(file);
       Log.debug("Removed: " + file);
       bChanges = true;
       if (reporter != null) {
         reporter.notifyFileOrPlaylistDropped();
       }
     }
   }
   return bChanges;
 }
 /* (non-Javadoc)
  * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent)
  */
 @Override
 @SuppressWarnings("unchecked")
 public void perform(ActionEvent e) {
   // TODO : rework this method into smaller units
   JComponent source = (JComponent) e.getSource();
   final List<Item> alSelected = (List<Item>) source.getClientProperty(Const.DETAIL_SELECTION);
   final List<Item> itemsToMove = ItemMoveManager.getInstance().getAll();
   final ItemMoveManager.MoveActions moveAction = ItemMoveManager.getInstance().getAction();
   final List<File> alFiles = new ArrayList<File>(alSelected.size());
   final List<Playlist> alPlaylists = new ArrayList<Playlist>(alSelected.size());
   final List<Directory> alDirs = new ArrayList<Directory>(alSelected.size());
   new Thread("Paste Thread") {
     @SuppressWarnings("cast")
     @Override
     public void run() {
       UtilGUI.waiting();
       // Compute all files to move from various items list
       if (itemsToMove.size() == 0) {
         Log.debug("None item to move");
         return;
       }
       Item first = itemsToMove.get(0);
       if (first instanceof Album || first instanceof Artist || first instanceof Genre) {
         List<Track> tracks = TrackManager.getInstance().getAssociatedTracks(itemsToMove, true);
         for (Track track : tracks) {
           alFiles.addAll(track.getFiles());
         }
       } else {
         for (Item item : itemsToMove) {
           if (item instanceof File) {
             alFiles.add((File) item);
           } else if (item instanceof Track) {
             alFiles.addAll(((Track) item).getFiles());
           } else if (item instanceof Directory) {
             alDirs.add((Directory) item);
           } else if (item instanceof Playlist) {
             alPlaylists.add((Playlist) item);
           }
         }
       }
       // Compute destination directory
       // alSelected can contain either a single Directory or a single Device
       Item item = alSelected.get(0);
       java.io.File dir;
       Directory destDir;
       if (item instanceof Directory) {
         dir = new java.io.File(((Directory) item).getAbsolutePath());
         destDir = (Directory) item;
       } else if (item instanceof Device) {
         dir = new java.io.File(((Device) item).getRootDirectory().getAbsolutePath());
         destDir = ((Device) item).getRootDirectory();
       } else {
         dir = ((File) item).getDirectory().getFio();
         destDir = ((File) item).getDirectory();
       }
       // Compute source directories
       // We need to find the highest directory in order to refresh it along
       // with the destination file to avoid phantom references
       List<Directory> srcDirs = new ArrayList<Directory>(1);
       for (File file : alFiles) {
         boolean parentAlreadyPresent = false;
         // We have to iterate using items index because the collection can
         // grow
         for (int i = 0; i < srcDirs.size(); i++) {
           Directory directory = (Directory) srcDirs.get(i);
           if (file.getDirectory().isChildOf(directory)) {
             parentAlreadyPresent = true;
             break;
           }
         }
         if (!parentAlreadyPresent && !srcDirs.contains(file.getDirectory())) {
           srcDirs.add(file.getDirectory());
         }
       }
       for (Playlist pl : alPlaylists) {
         boolean parentAlreadyPresent = false;
         // We have to iterate using items index because the collection can
         // grow
         for (int i = 0; i < srcDirs.size(); i++) {
           Directory directory = (Directory) srcDirs.get(i);
           if (pl.getDirectory().isChildOf(directory)) {
             parentAlreadyPresent = true;
             break;
           }
         }
         if (!parentAlreadyPresent && !srcDirs.contains(pl.getDirectory())) {
           srcDirs.add(pl.getDirectory());
         }
       }
       boolean overwriteAll = false;
       boolean bErrorOccured = false;
       if (moveAction == ItemMoveManager.MoveActions.CUT) {
         for (File f : alFiles) {
           if (!overwriteAll) {
             java.io.File newFile = new java.io.File(dir.getAbsolutePath() + "/" + f.getName());
             if (newFile.exists()) {
               int iResu =
                   Messages.getChoice(
                       Messages.getString("Confirmation_file_overwrite") + " : \n\n" + f.getName(),
                       Messages.YES_NO_ALL_CANCEL_OPTION,
                       JOptionPane.INFORMATION_MESSAGE);
               if (iResu == JOptionPane.NO_OPTION || iResu == JOptionPane.CANCEL_OPTION) {
                 UtilGUI.stopWaiting();
                 return;
               }
               if (iResu == Messages.ALL_OPTION) {
                 overwriteAll = true;
               }
             }
           }
           try {
             showMessage(f.getFIO());
             FileManager.getInstance().changeFileDirectory(f, destDir);
           } catch (Exception ioe) {
             Log.error(131, ioe);
             Messages.showErrorMessage(131);
             bErrorOccured = true;
           }
         }
         for (Playlist pl : alPlaylists) {
           if (!overwriteAll) {
             java.io.File newFile = new java.io.File(dir.getAbsolutePath() + "/" + pl.getName());
             if (newFile.exists()) {
               int iResu =
                   Messages.getChoice(
                       Messages.getString("Confirmation_file_overwrite")
                           + " : \n\n"
                           + pl.getName(),
                       Messages.YES_NO_ALL_CANCEL_OPTION,
                       JOptionPane.INFORMATION_MESSAGE);
               if (iResu == JOptionPane.NO_OPTION || iResu == JOptionPane.CANCEL_OPTION) {
                 UtilGUI.stopWaiting();
                 return;
               }
               if (iResu == Messages.ALL_OPTION) {
                 overwriteAll = true;
               }
             }
           }
           try {
             showMessage(pl.getFIO());
             final java.io.File fileNew =
                 new java.io.File(
                     new StringBuilder(dir.getAbsolutePath())
                         .append("/")
                         .append(pl.getName())
                         .toString());
             if (!pl.getFIO().renameTo(fileNew)) {
               throw new Exception(
                   "Cannot move item: "
                       + pl.getFIO().getAbsolutePath()
                       + " to "
                       + fileNew.getAbsolutePath());
             }
             // Refresh source and destination
             destDir.refresh(false);
             // Refresh source directories as well
             for (Directory srcDir : srcDirs) {
               srcDir.cleanRemovedFiles();
               srcDir.refresh(false);
             }
           } catch (Exception ioe) {
             Log.error(131, ioe);
             Messages.showErrorMessage(131);
             bErrorOccured = true;
           }
         }
         for (Directory d : alDirs) {
           try {
             java.io.File src = new java.io.File(d.getAbsolutePath());
             java.io.File dst = new java.io.File(dir.getAbsolutePath() + "/" + d.getName());
             showMessage(src);
             java.io.File newDir =
                 new java.io.File(new StringBuilder(dst.getAbsolutePath()).toString());
             if (!src.renameTo(newDir)) {
               throw new Exception(
                   "Cannot move item: " + src.getAbsolutePath() + " to " + dst.getAbsolutePath());
             }
             DirectoryManager.getInstance().removeDirectory(d.getID());
             destDir.refresh(false);
           } catch (Exception ioe) {
             Log.error(131, ioe);
             Messages.showErrorMessage(131);
             bErrorOccured = true;
           }
         }
         try {
           destDir.refresh(false);
           // Refresh source directories as well
           for (Directory srcDir : srcDirs) {
             srcDir.refresh(false);
           }
         } catch (Exception e1) {
           Log.error(e1);
           bErrorOccured = true;
         }
       } else if (moveAction == ItemMoveManager.MoveActions.COPY) {
         for (File f : alFiles) {
           if (!overwriteAll) {
             java.io.File newFile = new java.io.File(dir.getAbsolutePath() + "/" + f.getName());
             if (newFile.exists()) {
               int iResu =
                   Messages.getChoice(
                       Messages.getString("Confirmation_file_overwrite") + " : \n\n" + f.getName(),
                       Messages.YES_NO_ALL_CANCEL_OPTION,
                       JOptionPane.INFORMATION_MESSAGE);
               if (iResu == JOptionPane.NO_OPTION || iResu == JOptionPane.CANCEL_OPTION) {
                 UtilGUI.stopWaiting();
                 return;
               }
               if (iResu == Messages.ALL_OPTION) {
                 overwriteAll = true;
               }
             }
           }
           try {
             showMessage(f.getFIO());
             UtilSystem.copyToDir(f.getFIO(), dir);
           } catch (Exception ioe) {
             Log.error(131, ioe);
             Messages.showErrorMessage(131);
             bErrorOccured = true;
           }
         }
         for (Playlist pl : alPlaylists) {
           if (!overwriteAll) {
             java.io.File newFile = new java.io.File(dir.getAbsolutePath() + "/" + pl.getName());
             if (newFile.exists()) {
               int iResu =
                   Messages.getChoice(
                       Messages.getString("Confirmation_file_overwrite")
                           + " : \n\n"
                           + pl.getName(),
                       Messages.YES_NO_ALL_CANCEL_OPTION,
                       JOptionPane.INFORMATION_MESSAGE);
               if (iResu == JOptionPane.NO_OPTION || iResu == JOptionPane.CANCEL_OPTION) {
                 UtilGUI.stopWaiting();
                 return;
               }
               if (iResu == Messages.ALL_OPTION) {
                 overwriteAll = true;
               }
             }
           }
           try {
             showMessage(pl.getFIO());
             UtilSystem.copyToDir(pl.getFIO(), dir);
             // Refresh source and destination
             destDir.refresh(false);
             // Refresh source directories as well
             for (Directory srcDir : srcDirs) {
               srcDir.refresh(false);
             }
           } catch (Exception ioe) {
             Log.error(131, ioe);
             Messages.showErrorMessage(131);
             bErrorOccured = true;
           }
         }
         for (Directory d : alDirs) {
           try {
             java.io.File src = new java.io.File(d.getAbsolutePath());
             java.io.File dst = new java.io.File(dir.getAbsolutePath() + "/" + d.getName());
             showMessage(src);
             UtilSystem.copyRecursively(src, dst);
           } catch (Exception ioe) {
             Log.error(131, ioe);
             Messages.showErrorMessage(131);
             bErrorOccured = true;
           }
         }
         try {
           destDir.refresh(false);
         } catch (Exception e1) {
           Log.error(e1);
           bErrorOccured = true;
         }
       }
       ObservationManager.notify(new JajukEvent(JajukEvents.DEVICE_REFRESH));
       UtilGUI.stopWaiting();
       if (!bErrorOccured) {
         InformationJPanel.getInstance()
             .setMessage(Messages.getString("Success"), InformationJPanel.MessageType.INFORMATIVE);
       }
     }
   }.start();
 }
  /** 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;
  }