private ArrayList<Torrent> parseJsonRetrieveTorrents(JSONArray results) throws JSONException {
    ArrayList<Torrent> torrents = new ArrayList<Torrent>();

    if (results != null) {
      for (int i = 0; i < results.length(); i++) {

        JSONObject tor = results.getJSONObject(i);
        long done_bytes = tor.getLong("done_bytes");
        long total_bytes = tor.getLong("total_bytes");
        float percent = ((float) done_bytes / ((float) total_bytes + 1));

        // @formatter:off
        torrents.add(
            new Torrent(
                i,
                tor.getString("key"),
                tor.getString("name"),
                convertBitfluStatus(tor),
                "/" + settings.getOS().getPathSeperator(),
                tor.getInt("speed_download"),
                tor.getInt("speed_upload"),
                tor.getInt("active_clients"),
                tor.getInt(
                    "active_clients"), // Bitflu doesn't distinguish between seeders and leechers
                tor.getInt("clients"),
                tor.getInt("clients"), // Bitflu doesn't distinguish between seeders and leechers
                tor.getInt("eta"),
                done_bytes,
                tor.getLong("uploaded_bytes"),
                total_bytes,
                percent, // Percentage to [0..1]
                0f, // Not available
                null, // label
                null, // Not available
                null, // Not available
                null, // Not available
                settings.getType()));
        // @formatter:on
      }
    }
    // Return the list
    return torrents;
  }
 @Override
 public Daemon getType() {
   return settings.getType();
 }
  @SuppressWarnings("unchecked")
  private List<Torrent> onTorrentsRetrieved(Object result) throws DaemonException {

    Map<String, Object> response = (Map<String, Object>) result;

    // We might have an empty list if no torrents are on the server
    if (response == null) {
      return new ArrayList<Torrent>();
    }

    DLog.d(
        LOG_NAME,
        response.toString().length() > 300
            ? response.toString().substring(0, 300)
                + "... ("
                + response.toString().length()
                + " chars)"
            : response.toString());

    List<Torrent> torrents = new ArrayList<Torrent>();

    // Parse torrent list from Vuze response, which is a map list of ENTRYs
    for (String key : response.keySet()) {

      /**
       * Every Vuze ENTRY is a map of key-value pairs with information, or a key-map pair with that
       * map being a mapping of key-value pairs with information VuzeXmlTorrentListResponse.txt in
       * the Transdroid wiki shows a full example response, but it looks something like: ENTRY0={
       * position=1, torrent_file=/home/erickok/.azureus/torrents/ubuntu.torrent,
       * name=ubuntu-9.04-desktop-i386.iso, torrent={ size=732909568, creation_date=1240473087 } }
       */
      Map<String, Object> info = (Map<String, Object>) response.get(key);
      if (info == null
          || !info.containsKey("_object_id")
          || ((Long) info.get("_object_id")) == null) {
        // No valid XML data object returned
        throw new DaemonException(
            DaemonException.ExceptionType.UnexpectedResponse,
            "Map of objects returned by Vuze, but these object do not have some <info> attached or no <_object_id> is available");
      }
      Map<String, Object> torrentinfo = (Map<String, Object>) info.get("torrent");
      Map<String, Object> statsinfo = (Map<String, Object>) info.get("stats");
      Map<String, Object> scrapeinfo = (Map<String, Object>) info.get("scrape_result");
      Map<String, Object> announceinfo = (Map<String, Object>) info.get("announce_result");
      int scrapeSeedCount = ((Long) scrapeinfo.get("seed_count")).intValue();
      int scrapeNonSeedCount = ((Long) scrapeinfo.get("non_seed_count")).intValue();
      String error = (String) info.get("error_state_details");
      error = error != null && error.equals("") ? null : error;
      int announceSeedCount = ((Long) announceinfo.get("seed_count")).intValue();
      int announceNonSeedCount = ((Long) announceinfo.get("non_seed_count")).intValue();
      int rateDownload = ((Long) statsinfo.get("download_average")).intValue();
      Double availability = (Double) statsinfo.get("availability");
      Long size = torrentinfo != null ? (Long) torrentinfo.get("size") : 0;

      torrents.add(
          new Torrent(
              (Long) info.get("_object_id"), // id
              ((Long) info.get("_object_id"))
                  .toString(), // hash	//(String) torrentinfo.get("hash"), // hash
              (String) info.get("name").toString().trim(), // name
              convertTorrentStatus((Long) info.get("state")), // status
              (String) statsinfo.get("target_file_or_dir") + "/", // locationDir
              rateDownload, // rateDownload
              ((Long) statsinfo.get("upload_average")).intValue(), // rateUpload
              announceSeedCount, // seedersConnected
              scrapeSeedCount, // seedersKnown
              announceNonSeedCount, // leechersConnected
              scrapeNonSeedCount, // leechersKnown
              (rateDownload > 0
                  ? (int) ((Long) statsinfo.get("remaining") / rateDownload)
                  : -1), // eta (bytes left / rate download, if rate > 0)
              (Long) statsinfo.get("downloaded"), // downloadedEver
              (Long) statsinfo.get("uploaded"), // uploadedEver
              size, // totalSize
              (float) ((Long) statsinfo.get("downloaded"))
                  / (float) (size), // partDone (downloadedEver / totalSize)
              Math.min(availability.floatValue(), 1f),
              null, // TODO: Implement Vuze label support
              new Date((Long) statsinfo.get("time_started")), // dateAdded
              null, // Unsupported?
              error,
              settings.getType()));
    }

    return torrents;
  }