package page.tools.management;


import java.io.*;
import java.util.regex.Pattern;

import org.wikiwebserver.core.Privilege;
import org.wikiwebserver.core.WareHouse;
import org.wikiwebserver.core.SecurityMan;
import org.wikiwebserver.handler.http.FormData;
import org.wikiwebserver.handler.http.HTTPException;
import org.wikiwebserver.handler.http.interfaces.HTTPResponder;
import org.wikiwebserver.html.TemplatedPage;

import page.config.SiteTemplatedPage;

import static org.wikiwebserver.html.HTMLHelper.*;

public class SandBox extends SiteTemplatedPage implements HTTPResponder {

	
    public void generate() throws HTTPException {
        
        
        setTitle("Development Sandbox - WikiWebServer.org");
        addResourceRoot("/templates/default/sandbox/");
        addCSSLink("sandbox.css");
        addJavascriptLink("/page/tools/html/ajax.js");
        
        if (getFormData() != null) {
            String action = getFormData().getFirst("action");
            if (action != null && action.equals("Create new class")) {
                String className = getFormData().getFirst("classname");
                String error = verifyClassName(className);
                if (error != null) {
                    throw new HTTPException(500, error);
                }
                String classTypeString = getFormData().getFirst("classtype");
                int classType = getClassType(classTypeString);
                error = verifyClassType(classType);
                if (error != null) {
                    throw new HTTPException(500, error);
                }
                
                File userFile = getUserDir(getUser());
                if (!userFile.exists()) userFile.mkdirs();

                File targetFile = new File(userFile, className + ".java");
                String path = WareHouse.getUrlPathForFile(targetFile);
                
                try {
                    initialiseSource(className, classType);
                } catch (IOException ex) {
                    HTTPException httpe = new HTTPException(500, "Failed to initialise source");
                    httpe.initCause(ex);
                    throw httpe;
                }
                
                String editor = WareHouse.SOURCE_EDITOR_URL + "?path=" + path;
                String url = getServiceAddress() + editor;
                
                throw new HTTPException(302, "Edit new source", url);
            }
        }
        
        String httpResponder = "/edit?path=/org/wikiwebserver/http/interfaces/HTTPResponder.java";
        String corOvr = WareHouse.getUrlPathForClass(page.misc.CoreOverview.class);
        String devTips = WareHouse.getUrlPathForClass(page.misc.DevelopmentTips.class);
        String apiLink = "http://java.sun.com/javase/6/docs/api/";
        
        append("<h1>Development sandbox</h1>");
        append("<p>The sandbox has been designed to simplify creating new classes");
        append(" for WikiWebServer.</p>");
        append("<p>Every WikiWebServer page is generated by executing a class that");
        append(" implements the <a href='" + httpResponder + "'>HTTPResponder</a>");
        append(" interface. The class must generate");
        append(" valid content suitable for Internet browsers to interpret.");
        append("<p>Developing a class within WikiWebServer is very easy. No");
        append(" development tools are required - all you need is a web browser.</p>");
        append("<p>To jump start development, the sandbox creates a simple example class");
        append(" for you to modify.</p>");
        append("<p>Useful links: [ <a href='" + corOvr + "'>Core Overview</a> | " +
                    "<a href='" + devTips + "'>Development Tips</a>" +
                    " | <a href='" + apiLink + "'>Java API</a> ]");
        
        append("<h2>Create a new WikiWebServer class</h2>");
        
        if (getUser() == null) {
            append("<p>You must sign in  before you can develop on WikiWebServer.</p>");
        } 
        else if (getUser().getPrivilege().isBelow(Privilege.USER)) {
            append("<p>Not permitted to develop on WikiWebServer</p>");
        }
        else if (getUser().getPrivilege().isAbove(Privilege.GUEST)) {
            String action = getUrl();
            append("<form name='newclass' action='" + action + "'>");
            append("<p>1. Choose a name for your class:</p>");
            append("<input id='classname' type='text' name='classname' " +
                        "onkeyup='cpov(this, 300, \"post=classname\")' />");
            
            append("<div id='formDiv'>");
            append(getUpdatedForm());
            append("</div></form>");
        } 
        
        File userDir = getUserDir(getUser());
        if (userDir != null && userDir.listFiles() != null && userDir.listFiles().length > 0) {
            
            append("<h2>View or modify classes in your user directory</h2>");
            append("<p>To launch classes, click the .class file. To view or modify" +
                        " source code click edit besides the .java file.</p>");
         

            FileTreeView tree = new FileTreeView();
            appendToHead(tree.getHead());            
            append(tree.getFileTree("User directory", userDir, userDir));
            
        }
        
        if (getUser() == null) {
            // dont show
        }  
        else if (getUser().getPrivilege().isAbove(Privilege.GUEST)) {
            String uploadLink = WareHouse.getUrlPathForClass(page.tools.management.FileUploadPage.class);
            append("<p><a href='" + uploadLink + "'>Upload files to user directory</a>.</p>");
        }              

        
    } 
    

    
    private String getUserPackage(String className) {
        return "user.u" + getUser().getId();
    }    
    
    private String verifyClassName(String className) {
        if (className == null) return null;
        
        String test = className.replaceAll("\\$","\\\\\\$");
        
        if (test == null || test.length() == 0) {
            return "Please specify a class name.";
        } else if (!Pattern.matches("[A-Z]", test.substring(0, 1))) {
            return "A class name should start with a captial letter.";
        } else if (test.contains(" ")) {
            return "A class name can not contain spaces.";
        } else if (!Pattern.matches("[A-Za-z0-9_]++", test)) {
            return "Invalid character in class name.";
        } else if (!Pattern.matches("[A-Za-z0-9_]{1,20}", test)) {
            return "Class name too long.";
        }
        
        File userFile = getUserDir(getUser());
        if (!userFile.exists()) userFile.mkdirs();
        
        File localFile = new File(userFile, className + ".java");
        if (localFile.exists()) {
            return "A class with this name exists, choose another.";
        } else return null;
    }
    
    private String verifyClassType(int classType) {
        if (classType >= 0 && classType < jumpStartTypes.length) {
            return null;
        }
        return "Invalid class type";
    }
    
    private int getClassType(String classTypeString) {
        if (classTypeString != null && classTypeString.length() > 0) {
            return Integer.parseInt(classTypeString);
        }
        return -1;
    }
    
    public void ajax() {
        String content = WareHouse.escapeStringForJavaScript(getUpdatedForm());
        append("var ele = document.getElementById('formDiv');" + LF +
               "ele.innerHTML='" + content + "';");
    }
    
    private String getUpdatedForm() {
        
        FormData formData = getFormData();
        StringBuilder body = new StringBuilder();
        boolean useJavaScript = getPageType() != TemplatedPage.PAGE_TYPE_MOBILE;
        
        String className = null;
        String classNameError = null;
        String classTypeString = null;
        int classType = -1;
        String classTypeError = null;        
        
        if (formData != null) {
            String post = formData.getFirst("post");
            if (post != null && post.equals("classname")) {
                className = (String) getPostedData();
            }
            if (post != null && post.equals("classtype")) {
                className = formData.getFirst("classname");
                classTypeString = (String) getPostedData();
            }            
 
            classNameError = verifyClassName(className);
            
            body.append("<div id='classNameError'>");
            if (classNameError != null) body.append(classNameError);
            body.append("</div>");  
            
            classType = getClassType(classTypeString);
            classTypeError = verifyClassType(classType);
        }


        boolean enableTypes = className != null && classNameError == null;
              
        String step2Style = enableTypes || !useJavaScript ? "" : "unavailable";
        body.append("<div id='classType' class='" + step2Style + "'>");
        body.append("<p>2. What functionality do you wish to implement?</p>");    
        
        String dis = enableTypes ? "" : " disabled='true'";
        body.append("<div id='classTypesRadioDiv'>");
        
        for (int i=0; i<jumpStartTypes.length; i++) {
            String sel = "";
            if (i == classType) sel = " checked='true'";
            body.append("<input name='classtype' type='radio' value='" + i + "'" + sel);
            if (useJavaScript) {
                body.append(dis + " onclick='pov(this, \"post=classtype&amp;classname=" + className + "\");'/>");
            } else {
                body.append("/>");
            }
            body.append("&nbsp;" + jumpStartTypes[i][0] + "<br/>");
        } 
        body.append("</div>");
        
        boolean enableButton = className != null && classTypeError == null;
        if (enableButton || !useJavaScript) {
            body.append("<input class='createClassButton' type='submit' name='action' " +
                        "value='Create new class'/>");
        }
        body.append("</div>");         
        
        return body.toString();
    }
    
    private void initialiseSource(String newClassName, int classType) throws IOException {
        String oldPackageHead = "package " + jumpStartTypes[classType][1];
        String newPackageHead = "package " + getUserPackage(newClassName);   
        
        String oldClassNameHead = "class " + jumpStartTypes[classType][2];
        String newClassNameHead = "class " + newClassName;     
                    
        String source = WareHouse.getResourceAsString(jumpStartTypes[classType][3]);
        source = source.replaceFirst(oldPackageHead, newPackageHead);
        source = source.replaceFirst(oldClassNameHead, newClassNameHead);
        
        File target = new File(getUserDir(getUser()), newClassName + ".java");
        
        saveText(source, target);
    }    
    
    private void saveText(String utf8, File file) throws IOException {

        Writer out = null;
        try {
            // Establish privilege of current user. Writing must only be performed
            // if the user has sufficient privileges (not the executing class)
            SecurityMan bigNick = (SecurityMan) System.getSecurityManager();
            bigNick.checkWrite(file.toString(), getUser().getPrivilege());
            
            // Write the text to the filing system
            file.getParentFile().mkdirs();
            FileOutputStream fos = new FileOutputStream(file);
            out = new OutputStreamWriter(fos, "UTF8");
            out.write(utf8); 
            
        } catch (SecurityException ex) {
            ex.printStackTrace();
            throw new SecurityException("You do not have permission to save to " + file); 
        } finally {
            out.close();  
        }
    }   
    
    private static String[][] jumpStartTypes = new String[][] {
        { "Plain text response", 
            "page.example",
              "HelloWorld",
                "page/example/HelloWorld.java" },
              
        { "Web page with default style template", 
            "page.example",
              "HelloWorldPage",
                "page/example/HelloWorldPage.java" },
                
        { "Talking web page", 
            "page.example",
              "HelloWorldSpeech",
                "page/example/HelloWorldSpeech.java" },                
              
        { "Web page reading and writing persistent data", 
            "page.example",
              "Notepad",
                "page/example/Notepad.java" },
              
        { "Ajax live updating page", 
            "page.example",
               "AJAXUpdate",
                 "page/example/AJAXUpdate.java" },
                 
        { "Server push live updating page", 
            "page.example",
               "PushUpdate",
                 "page/example/PushUpdate.java" },                 
              
        { "Generate a dynamic image", 
            "image",
              "Example",
                "image/Example.java" },
    };
}

