package org.aktin.broker.download;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Instant;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.UUID;
import java.util.logging.Logger;

import javax.activation.DataSource;
import javax.inject.Singleton;

import org.aktin.broker.PathDataSource;



@Singleton
public class DownloadManager {
	private static final Logger log = Logger.getLogger(DownloadManager.class.getName());

	private long expirationMillis;
	private Hashtable<UUID, AbstractDownload> store;

	public DownloadManager() {
		store = new Hashtable<>();
		expirationMillis = 1000*60*10; // 10 minutes
	}

	public Download get(UUID id) throws IOException {
		cleanupExpired();
		return store.get(id);
	}

	/**
	 * Create download to a given local path. The path
	 * will not be deleted once the download expires.
	 * @param file path to download
	 * @return Download
	 */
	public Download createDataSourceDownload(DataSource ds) {
		DataSourceDownload download = new DataSourceDownload(ds);
		addDownload(download);
		return download;
	}

	private void addDownload(AbstractDownload download) {
		download.expiration = System.currentTimeMillis()+expirationMillis;
		download.id = UUID.randomUUID();

		store.put(download.id, download);
		log.info("Download added with UUID "+download.id);
	}
	/**
	 * Create a temporary file for download. Once the download
	 * expires, the file will be deleted.
	 * @return download
	 * @throws IOException IO error
	 */
	public Download createTemporaryFile(String mediaType) throws IOException {
		Path temp = Files.createTempFile("download",null);
		PathDataSource ds = new PathDataSource(temp, mediaType, Instant.now());
		DataSourceDownload download = new DataSourceDownload(ds, true);
		addDownload(download);
		return download;
	}

	/**
	 * Cleanup expired downloads.
	 * @throws IOException io error
	 */
	public void cleanupExpired() throws IOException{
		Iterator<Entry<UUID,AbstractDownload>> i = store.entrySet().iterator();
		long now = System.currentTimeMillis();
		while( i.hasNext() ) {
			AbstractDownload entry = i.next().getValue();
			if( entry.getExpireTimestamp() < now ) {
				log.info("Expired download "+entry.getId());
				i.remove();
				entry.postRemovalCleanup();
			}
		}
	}


}

@@ -389,16 +389,343 @@
 rce;%0A%0A%0A%0A
+/**%0A * Creates and manages downloads which expire after%0A * a predefined amount of time.%0A *%0A * This class is useful to separate authentication (needed to%0A * request downloads) from the actual download. The browser does%0A * not send authentication headers (e.g. bearer token) to%0A * download links.%0A *%0A * @author R.W.Majeed%0A *%0A */%0A
 @Singlet
@@ -926,16 +926,39 @@
 %3E store;
+%0A%09private Path tempDir;
 %0A%0A%09publi
@@ -1059,16 +1059,508 @@
 tes%0A%09%7D%0A%0A
+%09/**%0A%09 * Set the directory where temporary downloads will be%0A%09 * created and stored before they expire.%0A%09 * @param dir path to store temporary download files%0A%09 */%0A%09public void setTempDirectory(Path dir) %7B%0A%09%09this.tempDir = dir;%0A%09%7D%0A%0A%09/**%0A%09 * Retrieve a download for the given id. Non-existing%0A%09 * and expired downloads will return %7B@code null%7D.%0A%09 * @param id id for the download to be retrieved%0A%09 * @return download or %7B@code null%7D if not found or expired%0A%09 * @throws IOException IO error%0A%09 */%0A
 %09public 
@@ -1984,16 +1984,131 @@
 ad;%0A%09%7D%0A%0A
+%09/**%0A%09 * Set expiration date and unique id and add the download%0A%09 * to the list.%0A%09 * @param download download%0A%09 */%0A
 %09private
@@ -2590,16 +2590,16 @@
 ption %7B%0A
-
 %09%09Path t
@@ -2625,16 +2625,25 @@
 empFile(
+tempDir, 
 %22downloa

allow specification of temp directory, documentation