package page.tools.xml;

import java.io.IOException;
import java.io.StringWriter;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.wikiwebserver.handler.http.HTTPException;
import org.wikiwebserver.handler.http.HTTPHandler;
import org.wikiwebserver.handler.http.interfaces.HTTPResponder;

public class JNLPResponder implements HTTPResponder {
    
    private String jnlpSpec = "1.4+";
    private String j2seHref = "http://java.sun.com/products/autodl/j2se";

    private JavaProgramDetails program;
    
    public JNLPResponder(JavaProgramDetails program) {
        this.program = program;
    }    
    

    public Object respond(HTTPHandler conn) throws IOException {
        
        conn.getResponse().getHeaders().set("Content-Type", "application/x-java-jnlp-file");
        conn.getResponse().getHeaders().set("Content-disposition", "inline; " +
        		"filename=" + program.getName() + ".jnlp");
        
        return getJNLP();
    } 
    
    public String getJNLP() throws HTTPException {
        
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        try {
            DocumentBuilder db  = dbf.newDocumentBuilder();
            Document doc = db.newDocument();
            
            Element jnlp = doc.createElement("jnlp");
            jnlp.setAttribute("spec", jnlpSpec);
            jnlp.setAttribute("codebase", program.getCodebase());
            if (program.getHref() != null) {
                jnlp.setAttribute("href", program.getHref());
            }
            
            Element info = doc.createElement("information");
            Element infoTitle = doc.createElement("title");
            infoTitle.setTextContent(program.getName());
            Element infoVendor = doc.createElement("vendor");
            infoVendor.setTextContent(program.getVendor());       
            Element infoDescription = doc.createElement("description");
            infoDescription.setTextContent(program.getDescription80());   
            
            Element infoShortcut = doc.createElement("shortcut");
            infoShortcut.setAttribute("online", String.valueOf(program.isOnline()));
            Element infoShortcutDesktop = doc.createElement("desktop");
            Element infoShortcutMenu = doc.createElement("menu");
            infoShortcutMenu.setAttribute("submenu", program.getMenuTitle());
            infoShortcut.appendChild(infoShortcutDesktop);
            infoShortcut.appendChild(infoShortcutMenu);
           
            info.appendChild(infoTitle);
            info.appendChild(infoVendor);
            info.appendChild(infoDescription);
            if (program.getProgramIcon() != null) {
                Element infoIcon = doc.createElement("icon");
                infoIcon.setAttribute("href", program.getProgramIcon());                  
                info.appendChild(infoIcon);
            }
            if (program.getProgramSplash() != null) {
                Element infoSplash = doc.createElement("icon");
                infoSplash.setAttribute("kind", "splash");   
                infoSplash.setAttribute("href", program.getProgramSplash());                  
                info.appendChild(infoSplash);
            }
            info.appendChild(infoShortcut);
            if (!program.isOnline()) {
                Element offlineAllowed = doc.createElement("offline-allowed");                
                info.appendChild(offlineAllowed);
            }
                
            jnlp.appendChild(info);
            
            if (program.isAllPermissions()) {
                Element security = doc.createElement("security");
                Element securityPermission = doc.createElement("all-permissions");
                security.appendChild(securityPermission);   
                jnlp.appendChild(security);                
            }
            
            
            Element resources = doc.createElement("resources");
            Element resourcesJ2SE = doc.createElement("j2se");
            resourcesJ2SE.setAttribute("version", program.getJ2seVersion());
            resourcesJ2SE.setAttribute("initial-heap-size", program.getHeap());
            resourcesJ2SE.setAttribute("max-heap-size", program.getMaxHeap());
            resourcesJ2SE.setAttribute("href", j2seHref);
 
            if (program.getJaredResources() == null) {
                throw new HTTPException(500, "No Jared resources specified");
            }
            
            if (program.getProperties() != null) {
                for (Map.Entry<String, String> extension : program.getProperties().entrySet()) {
                    Element property = doc.createElement("property");
                    property.setAttribute("name", extension.getKey());
                    property.setAttribute("value", extension.getValue());
                    resources.appendChild(property); 
                }  
            }              
            
            for (String jar : program.getJaredResources()) {
                Element resourcesJar = doc.createElement("jar");
                resourcesJar.setAttribute("href", jar);
                // First jar is main
                if (resources.getChildNodes().getLength() == 0) {
                    resourcesJar.setAttribute("main", "true");
                }
                resources.appendChild(resourcesJar); 
            }
            
            if (program.getExtensions() != null) {
                for (Map.Entry<String, String> extension : program.getExtensions().entrySet()) {
                    Element resourcesExtension = doc.createElement("extension");
                    resourcesExtension.setAttribute("name", extension.getKey());
                    resourcesExtension.setAttribute("href", extension.getValue());
                    resources.appendChild(resourcesExtension); 
                }  
            }
            
          

            resources.appendChild(resourcesJ2SE);                    
            
            Element update = doc.createElement("update");
            update.setAttribute("check", "timeout");     
            update.setAttribute("policy", "always");  
            jnlp.appendChild(update);            
            
            jnlp.appendChild(resources);           
            
            Element app = doc.createElement("application-desc");
            app.setAttribute("main-class", program.getMainClass());
            
            if (program.getCommandLineArguments() != null) {
                for (String argument : program.getCommandLineArguments()) {
                    Element appArgument = doc.createElement("argument");
                    appArgument.setTextContent(argument);
                    app.appendChild(appArgument);    
                }
            }
            
            jnlp.appendChild(app);            
            
            doc.appendChild(jnlp);

            StringWriter writer = new StringWriter();
            
            // Prepare the DOM document for writing
            Source source = new DOMSource(doc);
            Result result = new StreamResult(writer);

            // Write the DOM document to the file
            Transformer xformer = TransformerFactory.newInstance().newTransformer();
            xformer.transform(source, result);
            
            writer.close();
            
            return writer.toString();
            
        } catch (Exception e) {
            throw new HTTPException(500, "Failed to generate JNLP", e);
        }
    }
}


