protected boolean connectResumable() throws IOException {
     // TODO: endrange pruefen
     long[] chunkProgress = downloadLink.getChunksProgress();
     String start, end;
     start = end = "";
     boolean rangeRequested = false;
     logger.info("chunksProgress: " + Arrays.toString(chunkProgress));
     if (downloadLink.getVerifiedFileSize() > 0) {
         start = chunkProgress[0] == 0 ? "0" : (chunkProgress[0] + 1) + "";
         end = (getFileSize() / chunkProgress.length) + "";
     } else {
         start = chunkProgress[0] == 0 ? "0" : (chunkProgress[0] + 1) + "";
         end = chunkProgress.length > 1 ? (chunkProgress[1] + 1) + "" : "";
     }
     if (downloadLink.getVerifiedFileSize() < 0 && start.equals("0")) {
         logger.info("rangeless resumable connect");
         rangeRequested = false;
         request.getHeaders().remove("Range");
     } else {
         rangeRequested = true;
         if (start.equalsIgnoreCase(end)) {
             logger.info("WTF, start equals end! Workaround: maybe manipulating the startRange?! it's about time for new downloadcore!");
         }
         request.getHeaders().put("Range", "bytes=" + start + "-" + end);
     }
     browser.connect(request);
     return rangeRequested;
 }
 protected void connectFirstRange() throws IOException {
     long fileSize = getFileSize();
     long part = fileSize / this.getChunkNum();
     boolean verifiedSize = downloadLink.getVerifiedFileSize() > 0;
     boolean openRangeRequested = false;
     if (verifiedSize == false || this.getChunkNum() == 1) {
         /* we only request a single range */
         openRangeRequested = true;
         /* Workaround for server responses != 206 */
         if (this.downloadLink.getBooleanProperty("ServerComaptibleForByteRangeRequest", false)) request.getHeaders().put("Range", "bytes=" + (0) + "-");
     } else {
         /* we request multiple ranges */
         openRangeRequested = false;
         request.getHeaders().put("Range", "bytes=" + (0) + "-" + (part - 1));
     }
     browser.connect(request);
     if (request.getHttpConnection().getResponseCode() == 416) {
         logger.warning("HTTP/1.1 416 Requested Range Not Satisfiable");
         if (this.plugin.getBrowser().isDebug()) logger.finest("\r\n" + request.printHeaders());
         throw new IllegalStateException("HTTP/1.1 416 Requested Range Not Satisfiable");
     } else if (request.getHttpConnection().getRange() == null) {
         logger.warning("No Chunkload");
         setChunkNum(1);
     } else {
         long[] range = request.getHttpConnection().getRange();
         if (range[0] != 0) {
             /* first range MUST start at zero */
             throw new IllegalStateException("Range Error. Requested " + request.getHeaders().get("Range") + ". Got range: " + request.getHttpConnection().getHeaderField("Content-Range"));
         } else if (verifiedSize && range[1] < (part - 1)) {
             /* response range != requested range */
             throw new IllegalStateException("Range Error. Requested " + request.getHeaders().get("Range") + " Got range: " + request.getHttpConnection().getHeaderField("Content-Range"));
         } else if (!openRangeRequested && range[1] == range[2] - 1 && getChunkNum() > 1) {
             logger.warning(" Chunkload Protection.. Requested " + request.getHeaders().get("Range") + " Got range: " + request.getHttpConnection().getHeaderField("Content-Range"));
             setChunkNum(1);
         } else if (verifiedSize && range[1] > (part - 1)) {
             /* response range is bigger than requested range */
             if (verifiedSize && range[1] == part) {
                 logger.severe("Workaround for buggy http server: rangeEND=contentEND, it must be rangeEND-1=contentEND as 0 is first byte!");
                 return;
             }
             throw new IllegalStateException("Range Error. Requested " + request.getHeaders().get("Range") + " Got range: " + request.getHttpConnection().getHeaderField("Content-Range"));
         }
     }
 }
    /**
     * 
     * @param downloadLink
     *            downloadlink der geladne werden soll (wird zur darstellung verwendet)
     * @param request
     *            Verbindung die geladen werden soll
     * @param b
     *            Resumefaehige verbindung
     * @param i
     *            max chunks. fuer negative werte wirden die chunks aus der config verwendet. Bsp: -3 : Min(3,Configwert);
     * @return
     * @throws IOException
     * @throws PluginException
     */
    public static DownloadInterface download(DownloadLink downloadLink, Request request, boolean b, int i) throws IOException, PluginException {
        /* disable gzip, because current downloadsystem cannot handle it correct */
        request.getHeaders().put("Accept-Encoding", null);
        RAFDownload dl = new RAFDownload(downloadLink.getLivePlugin(), downloadLink, request);
        PluginForHost plugin = downloadLink.getLivePlugin();
        if (plugin != null) plugin.setDownloadInterface(dl);
        if (i == 0) {
            dl.setChunkNum(JsonConfig.create(GeneralSettings.class).getMaxChunksPerFile());
        } else {
            dl.setChunkNum(i < 0 ? Math.min(i * -1, JsonConfig.create(GeneralSettings.class).getMaxChunksPerFile()) : i);
        }
        dl.setResume(b);
        return dl;

    }
 public URLConnectionAdapter connect() throws Exception {
     logger.finer("Connect...");
     if (request == null) throw new IllegalStateException("Wrong Mode. Instance is in direct Connection mode");
     this.connected = true;
     boolean resumed = false;
     if (this.isRangeRequestSupported() && this.checkResumabled()) {
         /* we can continue to resume the download */
         logger.finer(".....connectResumable");
         resumed = connectResumable();
     } else {
         long verifiedFileSize = downloadLink.getVerifiedFileSize();
         if (verifiedFileSize > 0 && getChunkNum() > 1) {
             /* check if we have to adapt the number of chunks */
             int tmp = Math.min(Math.max(1, (int) (verifiedFileSize / RAFChunk.MIN_CHUNKSIZE)), getChunkNum());
             if (tmp != getChunkNum()) {
                 logger.finer("Corrected Chunknum: " + getChunkNum() + " -->" + tmp);
                 setChunkNum(tmp);
             }
         }
         if (this.isRangeRequestSupported()) {
             /* range requests are supported! */
             logger.finer(".....connectFirstRange");
             connectFirstRange();
         } else {
             logger.finer(".....connectRangeless");
             /* our connection happens rangeless */
             request.getHeaders().remove("Range");
             /* Workaround for rayfile.com */
             if (this.downloadLink.getBooleanProperty("ServerComaptibleForByteRangeRequest", false)) {
                 if ("rayfile.com".contains(this.downloadLink.getHost())) request.getHeaders().put("Range", "bytes=" + (0) + "-");
             }
             browser.connect(request);
         }
     }
     if (this.plugin.getBrowser().isDebug()) logger.finest("\r\n" + request.printHeaders());
     connection = request.getHttpConnection();
     if (request.getLocation() != null) throw new PluginException(LinkStatus.ERROR_DOWNLOAD_FAILED, BrowserAdapter.ERROR_REDIRECTED);
     if (connection.getRange() != null) {
         /* we have a range response, let's use it */
         if (connection.getRange()[2] > 0) {
             this.setFilesizeCheck(true);
             this.downloadLink.setDownloadSize(connection.getRange()[2]);
         }
     } else if (resumed == false && connection.getLongContentLength() > 0 && connection.isOK()) {
         this.setFilesizeCheck(true);
         this.downloadLink.setDownloadSize(connection.getLongContentLength());
     }
     if (connection.getResponseCode() == 416 && resumed == true && downloadLink.getChunksProgress().length == 1 && downloadLink.getVerifiedFileSize() == downloadLink.getChunksProgress()[0] + 1) {
         logger.info("Faking Content-Disposition for already finished downloads");
         /* we requested a finished loaded file, got 416 and content-range with * and one chunk only */
         /* we fake a content disposition connection so plugins work normal */
         if (connection.isContentDisposition() == false) {
             List<String> list = new ArrayList<String>();
             list.add("fakeContent");
             connection.getHeaderFields().put("Content-Disposition", list);
         }
         List<String> list = new ArrayList<String>();
         list.add("application/octet-stream");
         connection.getHeaderFields().put("Content-Type", list);
         dlAlreadyFinished = true;
     }
     return connection;
 }