import java.io.IOException;
import java.io.InputStream;
import java.net.FileNameMap;
import java.net.URL;
import java.net.URLConnection;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.TimeZone;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * Serve assets from a ZIP file.
 * Based on python zipserve for GAE.
 * 
 * Instructions:
 * 
 * Configure the servlet as normal, map it to some path:
 * IE: /assets/*
 * The ZIPFILE servlet init parameter is required and should be the path and filename to the ZIP file containing the assets (relative to the classpath root)
 * IE: /com/myapp/assets/assets.zip
 * Append the path and filename of a file in the zipfile to the servlet request uri:
 * IE: http://someapp/assets/images/example.gif
 * 
 * @author Stian Lindhom
 *
 */
public class ZipServlet extends HttpServlet {

	private ZipFile zipFile;
	private FileNameMap fileNameMap;
	private static int MAX_AGE = 600;
	private static boolean PUBLIC = true;
	
	@Override
	public void init(ServletConfig config) throws ServletException {
		String zipFileName = config.getInitParameter("ZIPFILE");
		URL u = ZipServlet.class.getResource(zipFileName);
		try {
			zipFile = new ZipFile(u.getFile());
		} catch (IOException e) {
			throw new ServletException("Unable to open zip file (" + zipFileName + ")!");
		}
		
		fileNameMap = URLConnection.getFileNameMap();
		
		if (config.getInitParameter("PUBLIC") != null) {
			PUBLIC = Boolean.parseBoolean(config.getInitParameter("PUBLIC"));
		}
		
		if (config.getInitParameter("MAX_AGE") != null) {
			MAX_AGE = Integer.parseInt(config.getInitParameter("MAX_AGE"));
		}
	}

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		
		String zipEntryFilename = req.getPathInfo().substring(1);
		ZipEntry ze = zipFile.getEntry(zipEntryFilename);
		if (ze == null) {
			resp.setStatus(HttpServletResponse.SC_NOT_FOUND);
			return;
		}
		
		InputStream is = zipFile.getInputStream(ze);
		String mimeType = fileNameMap.getContentTypeFor(zipEntryFilename);
		resp.setContentType(mimeType);
		resp.setHeader("Cache-Control", PUBLIC?"public, ":"" + "max-age=" + MAX_AGE);

		SimpleDateFormat sdf = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z");
		sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
		Calendar c = Calendar.getInstance();
		c.add(Calendar.SECOND, MAX_AGE);
		resp.setHeader("Expires", sdf.format(c.getTime()));
		
		int i;
		while ((i = is.read()) != -1) {
			resp.getOutputStream().write(i);
		}
	}
}

