package collabode;

import java.io.*;
import java.net.URL;
import java.sql.*;
import java.util.Properties;
import java.util.Scanner;

import org.eclipse.core.resources.*;
import org.eclipse.core.runtime.*;
import org.eclipse.equinox.app.IApplication;
import org.eclipse.equinox.app.IApplicationContext;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.application.WorkbenchAdvisor;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleException;

import collabode.testing.ContinuousTesting;

public class Application implements IApplication {
    
    /**
     * The Collabode bundle.
     */
    public static Bundle BUNDLE;
    public static Shell SHELL;

    public Object start(IApplicationContext context) throws Exception {
        BUNDLE = Platform.getBundle("collabode.etherpad");
        
        String configFile;
        try {
            configFile = bundleResourcePath("config/collabode.properties");
        } catch (FileNotFoundException fnfe) {
            System.err.println("Missing config file: " + fnfe.getMessage());
            throw fnfe;
        }
        Properties config = new Properties();
        config.load(new FileInputStream(configFile));
        
        setupDatabase(config);
        startAppjet("--modulePath=" + bundleResourcePath("src"),
                    "--useVirtualFileRoot=" + bundleResourcePath("src"),
                    "--configFile=" + configFile);
        setupTesting(config);
        setupShutdown();
        
        final Display display = PlatformUI.createDisplay();
        PlatformUI.createAndRunWorkbench(display, new WorkbenchAdvisor() {
            @Override public boolean openWindows() { return true; } // XXX no window
            public String getInitialWindowPerspectiveId() { return null; }
            @Override public void postStartup() {
                SHELL = new Shell(display); // XXX maybe one window
                try {
                    Platform.getBundle("org.eclipse.jdt.ui").start();
                } catch (BundleException be) {
                    be.printStackTrace(); // XXX
                }
            }
        });
        
        return IApplication.EXIT_OK;
    }

    public void stop() {
    }
    
    public static String bundleResourcePath(String relativePath) throws IOException {
        URL url = BUNDLE.getResource(relativePath);
        if (url == null) { throw new FileNotFoundException("bundle resource: " + relativePath); }
        return FileLocator.toFileURL(url).getPath();
    }
    
    public static void setupDatabase(Properties config) throws Exception {
        Class.forName(config.getProperty("dbDriver"));
        Connection db = DriverManager.getConnection(config.getProperty("dbURL"), "u", "");
        Scanner schema = new Scanner(new File(bundleResourcePath("config/schema.sql"))).useDelimiter(";");
        String alreadyExists = config.getProperty("dbAlreadyExists");
        while (schema.hasNext()) {
            String stmt = schema.next().trim();
            if (stmt.isEmpty()) { continue; }
            try {
                db.createStatement().execute(stmt);
            } catch (SQLException sqle) {
                if ( ! sqle.getSQLState().equals(alreadyExists)) {
                    System.err.println(stmt);
                    System.err.println(sqle.getSQLState());
                    throw sqle;
                }
            }
        }
        db.close();
    }
    
    public static void startAppjet(String... args) {
        net.appjet.oui.main.main(args);
    }
    
    public static void setupTesting(Properties config) {
        ContinuousTesting tester = ContinuousTesting.getTester();
        new Thread(tester, "continuous testing").start();
        
        if ("true".equals(config.getProperty("continuousTesting"))) {
            Workspace.getWorkspace().addResourceChangeListener(tester.listener, IResourceChangeEvent.POST_CHANGE);
        }
    }
    
    private void setupShutdown() {
        new Thread(new Runnable() {
            public void run() {
                BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
                String line;
                try {
                    while ((line = br.readLine()) != null) {
                        if (line.equals("quit")) {
                            Workspace.scheduleTask("willShutdown");
                            PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() {
                                public void run() { PlatformUI.getWorkbench().close(); }
                            });
                        }
                    }
                } catch (IOException ioe) {
                    ioe.printStackTrace(); // XXX
                }
            }
        }, "console input").start();
    }
}

@@ -92,46 +92,67 @@
 til.
-Properties;%0Aimport java.util.Scanner;%0A
+*;%0A%0Aimport org.eclipse.core.resources.IResourceChangeEvent;
 %0Aimp
@@ -177,18 +177,26 @@
 re.r
-esources.*
+untime.FileLocator
 ;%0Aim
@@ -225,17 +225,24 @@
 runtime.
-*
+Platform
 ;%0Aimport
@@ -783,16 +783,62 @@
 l SHELL;
+%0A    public static Map%3CString, String%3E CONFIG;
 %0A%0A    pu
@@ -1342,24 +1342,51 @@
 nfigFile));%0A
+        setConfig(config);%0A
         %0A   
@@ -1404,22 +1404,16 @@
 atabase(
-config
 );%0A     
@@ -1617,22 +1617,16 @@
 Testing(
-config
 );%0A     
@@ -2684,32 +2684,195 @@
 %0A    %7D%0A    %0A    
+@SuppressWarnings(%7B %22rawtypes%22, %22unchecked%22 %7D)%0A    public static void setConfig(Map config) %7B%0A        CONFIG = Collections.unmodifiableMap(config);%0A    %7D%0A    %0A    
 public static vo
@@ -2888,33 +2888,16 @@
 atabase(
-Properties config
 ) throws
@@ -2931,34 +2931,26 @@
 forName(
-config.getProperty
+CONFIG.get
 (%22dbDriv
@@ -3008,34 +3008,26 @@
 nection(
-config.getProperty
+CONFIG.get
 (%22dbURL%22
@@ -3177,34 +3177,26 @@
 xists = 
-config.getProperty
+CONFIG.get
 (%22dbAlre
@@ -3867,33 +3867,16 @@
 Testing(
-Properties config
 ) %7B%0A    
@@ -4034,26 +4034,18 @@
 als(
-config.getProperty
+CONFIG.get
 (%22co

Make config settings generally accessible