/**
   * Tries to download updates.
   *
   * @return whether we had any non-hopeless updates.
   */
  private void downloadUpdates(
      List<? extends DownloadInformation> toDownload, ReplyHandler source) {
    if (toDownload == null) toDownload = Collections.emptyList();

    killObsoleteUpdates(toDownload);

    for (DownloadInformation next : toDownload) {
      if (isHopeless(next)) continue;

      if (downloadManager.get().isSavedDownloadsLoaded()
          && fileManager.get().getManagedFileList().isLoadFinished()) {

        // TODO: remove the cast
        ManagedDownloader md =
            (ManagedDownloader) downloadManager.get().getDownloaderForURN(next.getUpdateURN());

        // Skip to the next one since we already have a complete file.
        if (hasCompleteFile(next.getUpdateURN())) {
          if (md != null) {
            md.stop(false);
          }
          continue;
        }

        // If we don't have an existing download ...
        // and there's no existing InNetwork downloads &
        // no existing Store downloads &
        // we're allowed to start a new one.
        if (md == null && !downloadManager.get().hasInNetworkDownload() && canStartDownload()) {
          LOG.debug("Starting a new InNetwork Download");
          try {
            md = (ManagedDownloader) downloadManager.get().download(next, clock.now());
          } catch (SaveLocationException sle) {
            LOG.error("Unable to construct download", sle);
          }
        }

        if (md != null) {
          if (source != null) md.addDownload(rfd(source, next), false);
          else addCurrentDownloadSources(md, next);
        }
      }
    }
  }
  /** @return whether we killed any hopeless update downloads */
  private void killHopelessUpdates(List<? extends DownloadInformation> updates) {
    if (updates == null) return;

    if (!downloadManager.get().hasInNetworkDownload()) return;

    long now = clock.now();
    for (DownloadInformation info : updates) {
      Downloader downloader = downloadManager.get().getDownloaderForURN(info.getUpdateURN());
      if (downloader != null && downloader instanceof InNetworkDownloader) {
        InNetworkDownloader iDownloader = (InNetworkDownloader) downloader;
        if (isHopeless(iDownloader, now)) iDownloader.stop(false);
      }
    }
  }
 /** Constructs an RFD out of the given information & connection. */
 private RemoteFileDesc rfd(ReplyHandler rh, DownloadInformation info) {
   Set<URN> urns = new UrnSet(info.getUpdateURN());
   return remoteFileDescFactory.createRemoteFileDesc(
       new ConnectableImpl(
           rh.getInetSocketAddress(),
           rh instanceof Connectable ? ((Connectable) rh).isTLSCapable() : false),
       Integer.MAX_VALUE,
       info.getUpdateFileName(),
       info.getSize(),
       rh.getClientGUID(),
       0,
       false,
       2,
       false,
       null,
       urns,
       false,
       "LIME",
       -1);
 }
  /**
   * kills all in-network downloaders whose URNs are not listed in the list of updates. Deletes any
   * files in the folder that are not listed in the update message.
   */
  private void killObsoleteUpdates(List<? extends DownloadInformation> toDownload) {
    if (!downloadManager.get().isSavedDownloadsLoaded()
        || !fileManager.get().getManagedFileList().isLoadFinished()) return;

    if (_killingObsoleteNecessary) {
      _killingObsoleteNecessary = false;
      downloadManager.get().killDownloadersNotListed(toDownload);

      Set<URN> urns = new HashSet<URN>(toDownload.size());
      for (DownloadInformation data : toDownload) urns.add(data.getUpdateURN());

      List<FileDesc> shared =
          fileManager
              .get()
              .getGnutellaFileList()
              .getFilesInDirectory(LibraryUtils.PREFERENCE_SHARE);
      for (FileDesc fd : shared) {
        if (fd.getSHA1Urn() != null && !urns.contains(fd.getSHA1Urn())) {
          fileManager.get().getManagedFileList().remove(fd.getFile());
          fd.getFile().delete();
        }
      }
    }
  }
 /** @return if the given update is considered hopeless */
 private static boolean isHopeless(DownloadInformation info) {
   return UpdateSettings.FAILED_UPDATES.contains(info.getUpdateURN().httpStringValue());
 }