protected void onChunksReady() {
        logger.info("Close connections if they are not closed yet");
        try {
            for (RAFChunk c : this.getChunks()) {
                c.closeConnections();
            }
        } finally {
            logger.info("Close File. Let AV programs run");
            try {
                outputPartFile.close();
            } catch (Throwable e) {
            }
        }
        downloadLink.getLinkStatus().setStatusText(null);
        if (!handleErrors()) return;
        try {
            File part = new File(outputCompleteFile.getAbsolutePath() + ".part");
            /* lets check the hash/crc/sfv */
            if (JsonConfig.create(GeneralSettings.class).isHashCheckEnabled()) {
                synchronized (HASHCHECKLOCK) {
                    /*
                     * we only want one hashcheck running at the same time. many finished downloads can cause heavy diskusage here
                     */
                    String hash = null;
                    String type = null;
                    Boolean success = null;

                    // StatsManager
                    if ((hash = downloadLink.getMD5Hash()) != null && hash.length() == 32) {
                        /* MD5 Check */
                        type = "MD5";
                        downloadLink.getLinkStatus().setStatusText(_JDT._.system_download_doCRC2("MD5"));
                        String hashFile = Hash.getMD5(part);
                        success = hash.equalsIgnoreCase(hashFile);
                    } else if (!StringUtils.isEmpty(hash = downloadLink.getSha1Hash()) && hash.length() == 40) {
                        /* SHA1 Check */
                        type = "SHA1";
                        downloadLink.getLinkStatus().setStatusText(_JDT._.system_download_doCRC2("SHA1"));
                        String hashFile = Hash.getSHA1(part);
                        success = hash.equalsIgnoreCase(hashFile);
                    } else if ((hash = new Regex(downloadLink.getName(), ".*?\\[([A-Fa-f0-9]{8})\\]").getMatch(0)) != null) {
                        type = "CRC32";
                        String hashFile = Long.toHexString(Hash.getCRC32(part));
                        success = hash.equalsIgnoreCase(hashFile);
                    } else {
                        DownloadLink sfv = null;
                        synchronized (downloadLink.getFilePackage()) {
                            for (DownloadLink dl : downloadLink.getFilePackage().getChildren()) {
                                if (dl.getFileOutput().toLowerCase().endsWith(".sfv")) {
                                    sfv = dl;
                                    break;
                                }
                            }
                        }
                        /* SFV File Available, lets use it */
                        if (sfv != null && sfv.getLinkStatus().hasStatus(LinkStatus.FINISHED)) {
                            String sfvText = IO.readFileToString(new File(sfv.getFileOutput()));
                            if (sfvText != null) {
                                /* Delete comments */
                                sfvText = sfvText.replaceAll(";(.*?)[\r\n]{1,2}", "");
                                if (sfvText != null && sfvText.contains(downloadLink.getName())) {
                                    downloadLink.getLinkStatus().setStatusText(_JDT._.system_download_doCRC2("CRC32"));
                                    type = "CRC32";
                                    String crc = Long.toHexString(Hash.getCRC32(part));
                                    success = new Regex(sfvText, downloadLink.getName() + "\\s*" + crc).matches();
                                }
                            }
                        }
                    }
                    if (success != null) {
                        hashCheckFinished(type, success);
                    }
                }
            }

            boolean renameOkay = false;
            int retry = 5;
            /* rename part file to final filename */
            while (retry > 0) {
                /* first we try normal rename method */
                if ((renameOkay = part.renameTo(outputCompleteFile)) == true) {
                    break;
                }
                /* this may fail because something might lock the file */
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    break;
                }
                retry--;
            }
            /* Fallback */
            if (renameOkay == false) {
                /* rename failed, lets try fallback */
                logger.severe("Could not rename file " + part + " to " + outputCompleteFile);
                logger.severe("Try copy workaround!");
                try {
                    //DISKSPACECHECK freeSpace = DownloadWatchDog.getInstance().checkFreeDiskSpace(part.getParentFile(), part.length());
                    //if (DISKSPACECHECK.FAILED.equals(freeSpace)) throw new Throwable("not enough diskspace free to copy part to complete file");
                    IO.copyFile(part, outputCompleteFile);
                    renameOkay = true;
                    part.deleteOnExit();
                    part.delete();
                } catch (Throwable e) {
                    LogSource.exception(logger, e);
                    /* error happened, lets delete complete file */
                    if (outputCompleteFile.exists() && outputCompleteFile.length() != part.length()) {
                        outputCompleteFile.delete();
                        outputCompleteFile.deleteOnExit();
                    }
                }
                if (!renameOkay) {
                    logger.severe("Copy workaround: :(");
                    error(LinkStatus.ERROR_LOCAL_IO, _JDT._.system_download_errors_couldnotrename());
                } else {
                    logger.severe("Copy workaround: :)");
                }
            }
            if (renameOkay) {

                /*if (StatsManager.I().isEnabled()) {
                    long speed = 0;
                    long startDelay = -1;
                    try {
                        speed = (outputCompleteFile.length() - Math.max(0, sizeBefore)) / ((System.currentTimeMillis() - getStartTimeStamp()) / 1000);
                    } catch (final Throwable e) {
                        LogSource.exception(logger, e);
                    }
                    try {
                        startDelay = System.currentTimeMillis() - downloadLink.getDownloadLinkController().getStartTimestamp();
                    } catch (final Throwable e) {
                        LogSource.exception(logger, e);
                    }
                    StatsManager.I().onFileDownloaded(outputCompleteFile, downloadLink, speed, startDelay, getChunks().size());
                }*/

                /* save absolutepath as final location property */
                downloadLink.setProperty(DownloadLink.PROPERTY_FINALLOCATION, outputCompleteFile.getAbsolutePath());
                Date last = TimeFormatter.parseDateString(connection.getHeaderField("Last-Modified"));
                if (last != null && JsonConfig.create(GeneralSettings.class).isUseOriginalLastModified()) {
                    /* set original lastModified timestamp */
                    outputCompleteFile.setLastModified(last.getTime());
                } else {
                    /* set current timestamp as lastModified timestamp */
                    outputCompleteFile.setLastModified(System.currentTimeMillis());
                }
            }
        } catch (Exception e) {
            logger.log(Level.SEVERE, "Exception", e);
            addException(e);
        }
    }