package page.tools.jar;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedList;
import java.util.jar.Attributes;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import org.wikiwebserver.core.WikiWebServer;
import org.wikiwebserver.handler.http.HTTPHandler;
import org.wikiwebserver.handler.http.HTTPHeaders;
import org.wikiwebserver.handler.http.interfaces.HTTPResponder;

public class CoreJarResponder implements HTTPResponder {
    
    public Manifest getManifest() {
        
        Manifest manifest = new Manifest();
        Attributes attribs = manifest.getMainAttributes();
        attribs.put(Attributes.Name.MANIFEST_VERSION, "1.2");
        attribs.put(Attributes.Name.IMPLEMENTATION_TITLE, "WikiWebServer Core");
        attribs.put(Attributes.Name.IMPLEMENTATION_URL, "http://www.wikiwebserver.org/");
        attribs.put(Attributes.Name.IMPLEMENTATION_VERSION, WikiWebServer.VERSION_CODE);
        attribs.put(Attributes.Name.MAIN_CLASS, WikiWebServer.class.getName());
        
        return manifest;
    }
    
    public Collection<File> getFilesForJar() {
        return getClassFiles(new File("org/wikiwebserver/core").listFiles());
    }
    
    public Collection<File> getClassFiles(File[] allFiles) {
        Collection<File> files = new LinkedList<File>();
        for (File file : allFiles) {
            if (file.isDirectory()) {
                files.addAll(Arrays.asList(file.listFiles()));
            }
            else if (file.getName().endsWith(".class")) files.add(file);
        }
        return files;    
    }
    
    public String getContentDisposition() {
        return "inline; filename=\"WikiWebServerCore.jar\"";
    }
	
    public Object respond(HTTPHandler conn) {
        
        HTTPHeaders headers = conn.getResponse().getHeaders();
        
        // headers.put("Content-Type", "application/java"); // Causes problems
        headers.set("Pragma", "no-cache");
        headers.set("Cache-Control", "no-cache");             
        headers.set("Content-Type", "application/octet-stream");
        headers.set("Content-disposition", getContentDisposition()); 
        
        try {
            JarOutputStream jarOut = new JarOutputStream(conn.getOutputStream(), getManifest());
            jarOut.setMethod(ZipOutputStream.DEFLATED); 

            File root = new File(".");

            for (File file : getFilesForJar()) {
                writeFile(root, file, jarOut);
            }
            jarOut.close();
            
        } catch (IOException ex) {
            ex.printStackTrace();
        }       
        
        return null;
    } 
    
    public void writeFile(File base, File file, ZipOutputStream out) throws IOException {
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            for (int i=0; i<files.length; i++) {
                writeFile(base, files[i], out);
            } 
        }
        else {
            String path = file.getName();
            if (base != null) {
                String baseFileString = base.getCanonicalFile().toString();
                String fileString = file.getCanonicalFile().toString();
                path = fileString.substring(baseFileString.length());
                if (path.startsWith(File.separator)) {
                    path = path.substring(1);
                }
                path = path.replace('\\', '/');
            }
            ZipEntry entry = new ZipEntry(path);
            out.putNextEntry(entry);
            
            InputStream in = null;
            try {
                in = new FileInputStream(file);  
                int bufferSize = file.length() < 10240 ? (int)file.length() : 10240;
                byte[] buffer = new byte[bufferSize];        
                int r = in.read(buffer);
                while(r > 0) {
                    out.write(buffer, 0, r);            
                    r = in.read(buffer);
                }
            } catch (IOException ex) {
                throw ex;
            } finally {
                if (in != null) in.close();
            }
        }
    }  
}
