package net.oni2.aeinstaller.backend.packages.download; import java.util.Date; import java.util.TreeSet; import java.util.Vector; import net.oni2.aeinstaller.backend.packages.Package; import net.oni2.aeinstaller.backend.packages.download.ModDownload.ModDownloadState; /** * @author Christian Illy */ public class ModDownloader implements ModDownloadListener { /** * @author Christian Illy */ public enum State { /** * Downloads running */ RUNNING, /** * Aborted because of an error */ ERROR, /** * Downloads interrupted */ INTERRUPTED, /** * When the last file was downloaded and only unpacking is left */ LAST_FILE_DOWNLOADED, /** * Everything completed */ FINISHED }; private int currentDownload = -1; private int unpacked = 0; private Vector downloads = new Vector(); private int totalSize = 0; private int downloadedComplete = 0; private int downloadedCurrent = 0; private long startMS; private State state = State.RUNNING; private ModDownloaderListener listener; /** * Create a mods-download-process * * @param mods * Mods to download * @param listener * Listener for status updates */ public ModDownloader(TreeSet mods, ModDownloaderListener listener) { this.listener = listener; for (Package m : mods) { downloads.add(new ModDownload(m, this)); totalSize += m.getZipSize(); } startMS = new Date().getTime(); startNextDownload(); } private void startNextDownload() { if (currentDownload >= 0) downloadedComplete += downloads.get(currentDownload).getSize(); currentDownload++; downloadedCurrent = 0; if ((state == State.RUNNING) && (currentDownload < downloads.size())) { downloads.get(currentDownload).start(); } else if (state == State.RUNNING) { state = State.LAST_FILE_DOWNLOADED; notifyListener(); } else { notifyListener(); } } private int getTimeElapsed() { int total = (int) (new Date().getTime() - startMS); return total; } private int getDownloadSpeed() { int elap = getTimeElapsed(); long down = downloadedComplete + downloadedCurrent; if (elap > 0) return (int)(down * 1000 / elap); else return 1; } private int getTimeRemaining() { int remainingSize = totalSize - (downloadedComplete + downloadedCurrent); return remainingSize / getDownloadSpeed(); } private void notifyListener() { if (currentDownload < downloads.size()) { listener.updateStatus(this, downloads.get(currentDownload).getMod(), state, unpacked, downloads.size(), downloadedComplete + downloadedCurrent, totalSize, getTimeElapsed() / 1000, getTimeRemaining(), getDownloadSpeed()); } else { listener.updateStatus(this, null, state, unpacked, downloads.size(), downloadedComplete + downloadedCurrent, totalSize, getTimeElapsed() / 1000, getTimeRemaining(), getDownloadSpeed()); } } /** * @return total download size */ public int getTotalSize() { return totalSize; } /** * @return Is this process finished */ public boolean isFinished() { return state == State.FINISHED; } @Override public void modDownloadStatusUpdate(ModDownload source, ModDownloadState state, int done, int total) { switch (state) { case RUNNING: downloadedCurrent = done; notifyListener(); break; case ERROR: this.state = State.ERROR; break; case DOWNLOADED: if (source == downloads.get(currentDownload)) startNextDownload(); break; case UNPACKED: source.getMod().updateLocalData(); unpacked++; if (unpacked >= downloads.size()) this.state = State.FINISHED; notifyListener(); break; case INIT: break; case INTERRUPTED: break; } } /** * Abort download process */ public void abort() { if (currentDownload < downloads.size()) { state = State.INTERRUPTED; ModDownload md = downloads.get(currentDownload); md.abort(); } } }