/**
  * Handles actually copying and writing the playlist to disk.
  *
  * @param path - file location to save the list to
  */
 private void saveM3U(final Playlist playlist, final String path) {
   BackgroundExecutorService.schedule(
       new Runnable() {
         public void run() {
           try {
             List<File> files = new ArrayList<File>();
             List<PlaylistItem> items = playlist.getItems();
             for (PlaylistItem item : items) {
               File file = new File(item.getFilePath());
               if (file.exists()) {
                 files.add(file);
               }
             }
             M3UPlaylist.save(path, files);
           } catch (Exception e) {
             e.printStackTrace();
             GUIMediator.safeInvokeLater(
                 new Runnable() {
                   public void run() {
                     GUIMediator.showError("Unable to save playlist");
                   }
                 });
           }
         }
       });
 }
  /**
   * Updates the Table based on the selection of the given table. Perform lookups to remove any
   * store files from the shared folder view and to only display store files in the store view
   */
  void updateTableFiles(DirectoryHolder dirHolder) {
    if (dirHolder == null) {
      return;
    }

    if (dirHolder instanceof MediaTypeSavedFilesDirectoryHolder) {
      MediaType mediaType = ((MediaTypeSavedFilesDirectoryHolder) dirHolder).getMediaType();
      setMediaType(mediaType);

      if (mediaType.equals(MediaType.getAudioMediaType())) {
        UXStats.instance().log(UXAction.LIBRARY_BROWSE_FILE_TYPE_AUDIO);
      } else if (mediaType == MediaType.getImageMediaType()) {
        UXStats.instance().log(UXAction.LIBRARY_BROWSE_FILE_TYPE_PICTURES);
      } else if (mediaType == MediaType.getDocumentMediaType()) {
        UXStats.instance().log(UXAction.LIBRARY_BROWSE_FILE_TYPE_DOCUMENTS);
      } else if (mediaType == MediaType.getVideoMediaType()) {
        UXStats.instance().log(UXAction.LIBRARY_BROWSE_FILE_TYPE_VIDEOS);
      } else if (mediaType == MediaType.getTorrentMediaType()) {
        UXStats.instance().log(UXAction.LIBRARY_BROWSE_FILE_TYPE_TORRENTS);
      } else if (mediaType == MediaType.getProgramMediaType()) {
        UXStats.instance().log(UXAction.LIBRARY_BROWSE_FILE_TYPE_APPLICATIONS);
      }
    } else {
      setMediaType(MediaType.getAnyTypeMediaType());
    }
    clearTable();

    List<List<File>> partitionedFiles = split(100, Arrays.asList(dirHolder.getFiles()));

    for (List<File> partition : partitionedFiles) {
      final List<File> fPartition = partition;

      BackgroundExecutorService.schedule(
          new Runnable() {

            @Override
            public void run() {
              for (final File file : fPartition) {
                GUIMediator.safeInvokeLater(
                    new Runnable() {
                      public void run() {
                        addUnsorted(file);
                      }
                    });
              }

              GUIMediator.safeInvokeLater(
                  new Runnable() {
                    public void run() {
                      LibraryMediator.instance().getLibrarySearch().addResults(fPartition.size());
                    }
                  });
            }
          });
    }

    forceResort();
  }
 /**
  * Performs the actual reading of the PlayList and generation of the PlayListItems from the
  * PlayList. Once we have done the heavy weight construction of the PlayListItem list, the list is
  * handed to the swing event queue to process adding the files to the actual table model
  *
  * @param selFile - file that we're reading from
  * @param path - path of file to open
  * @param overwrite - true if the table should be cleared of all entries prior to loading the new
  *     playlist
  */
 private void loadM3U(final Playlist playlist, final File selFile, final String path) {
   BackgroundExecutorService.schedule(
       new Runnable() {
         public void run() {
           try {
             final List<File> files = M3UPlaylist.load(path);
             if (playlist != null) {
               LibraryUtils.asyncAddToPlaylist(playlist, files.toArray(new File[0]));
             } else {
               LibraryUtils.createNewPlaylist(files.toArray(new File[0]));
             }
           } catch (Exception e) {
             e.printStackTrace();
             GUIMediator.safeInvokeLater(
                 new Runnable() {
                   public void run() {
                     GUIMediator.showError("Unable to save playlist");
                   }
                 });
           }
         }
       });
 }
    private void copyPlaylistFilesToFolder(Playlist playlist) {
      if (playlist == null || playlist.getItems().isEmpty()) {
        return;
      }

      File suggestedDirectory = FileChooserHandler.getLastInputDirectory();
      if (suggestedDirectory.equals(CommonUtils.getCurrentDirectory())) {
        suggestedDirectory = new File(CommonUtils.getUserHomeDir(), "Desktop");
      }

      final File selFolder =
          FileChooserHandler.getSaveAsDir(
              GUIMediator.getAppFrame(),
              I18nMarker.marktr("Where do you want the playlist files copied to?"),
              suggestedDirectory);

      if (selFolder == null) {
        return;
      }

      // let's make a copy of the list in case the playlist will be modified during the copying.
      final List<PlaylistItem> playlistItems = new ArrayList<>(playlist.getItems());

      BackgroundExecutorService.schedule(
          new Thread("Library-copy-playlist-files") {
            @Override
            public void run() {

              int n = 0;
              int total = playlistItems.size();
              String targetName = selFolder.getName();

              for (PlaylistItem item : playlistItems) {
                File f = new File(item.getFilePath());
                if (f.isFile() && f.exists() && f.canRead()) {
                  try {
                    Path source = f.toPath();
                    Path target =
                        FileSystems.getDefault().getPath(selFolder.getAbsolutePath(), f.getName());
                    Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
                    n++;

                    // invoked on UI thread later
                    String status = String.format("Copied %d of %d to %s", n, total, targetName);
                    LibraryMediator.instance().getLibrarySearch().pushStatus(status);
                  } catch (IOException e) {
                    e.printStackTrace();
                  }
                }
              }

              GUIMediator.launchExplorer(selFolder);

              // and clear the output
              try {
                Thread.sleep(2000);
                LibraryMediator.instance().getLibrarySearch().pushStatus("");
              } catch (InterruptedException e) {
              }
            }
          });
    }