package bamboo.app;

import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import spark.Spark;
import spark.embeddedserver.EmbeddedServer;
import spark.embeddedserver.EmbeddedServers;
import spark.embeddedserver.jetty.EmbeddedJettyFactory;
import spark.embeddedserver.jetty.EmbeddedJettyServer;
import spark.embeddedserver.jetty.JettyHandler;
import spark.http.matching.MatcherFilter;
import spark.route.Routes;
import spark.staticfiles.StaticFilesConfiguration;

import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;

public class Main {

    public static void main(String args[]) throws Throwable {
        if (args.length > 0 && args[0].equals("server")) {
            server(Arrays.copyOfRange(args, 1, args.length));
            return;
        }
        // we load all application classes via reflection to ensure they're loaded via JShotgun's
        // classloader when in server mode instead of in the parent classloader
        try {
            Class.forName("bamboo.app.CLI").getMethod("main", String[].class).invoke(null, (Object) args);
        } catch (InvocationTargetException e) {
            throw e.getCause();
        }
    }

    private static void serverUsage() {
        System.err.println("Usage: java " + Bamboo.class.getName() + " [-b bindaddr] [-p port] [-i]");
        System.err.println("");
        System.err.println("  -b bindaddr   Bind to a particular IP address");
        System.err.println("  -p port       Local port to listen on");
        System.err.println("  -c path       Set context path");
    }

    public static void server(String[] args) throws IOException, InterruptedException {
        int port = 8080;
        String host = null;
        String contextPath = null;
        for (int i = 0; i < args.length; i++) {
            switch (args[i]) {
                case "-p":
                    port = Integer.parseInt(args[++i]);
                    break;
                case "-b":
                    host = args[++i];
                    break;
                case "-c":
                    contextPath = args[++i];
                    break;
                default:
                    serverUsage();
                    System.exit(1);
            }
        }
        Spark.port(port);
        if (host != null) {
            Spark.ipAddress(host);
        }

        if (contextPath != null) {
            String path = contextPath;
            EmbeddedServers.add(EmbeddedServers.Identifiers.JETTY, new EmbeddedJettyFactory() {
                @Override
                public EmbeddedServer create(Routes routeMatcher, StaticFilesConfiguration staticFilesConfiguration, boolean hasMultipleHandler) {
                    MatcherFilter matcherFilter = new MatcherFilter(routeMatcher, staticFilesConfiguration, false, hasMultipleHandler);
                    matcherFilter.init((FilterConfig) null);
                    JettyHandler handler = new JettyHandler(matcherFilter) {
                        @Override
                        public void doHandle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
                            request = new HttpServletRequestWrapper(request) {
                                @Override
                                public String getRequestURI() {
                                    // Spark unfortunately uses getRequestURI() for routing rather than pathInfo
                                    // so we work around it here.
                                    return super.getRequestURI().substring(path.length());
                                }
                            };
                            super.doHandle(target, baseRequest, request, response);
                        }
                    };
                    ServletContextHandler servletContextHandler = new ServletContextHandler();
                    servletContextHandler.setContextPath(path);
                    servletContextHandler.setHandler(handler);
                    return new EmbeddedJettyServer((i, j, k) -> {
                        Server server = new Server();
                        return server;
                    }, servletContextHandler);
                }
            });
        }

        try (Webapp webapp = new Webapp()) {
            Spark.awaitInitialization();
            while (true) {
                Thread.sleep(1000000000);
            }
        }
    }
}
@@ -102,32 +102,81 @@
 ContextHandler;%0A
+import org.eclipse.jetty.util.thread.ThreadPool;%0A
 import spark.Spa
@@ -423,24 +423,78 @@
 ttyHandler;%0A
+import spark.embeddedserver.jetty.JettyServerFactory;%0A
 import spark
@@ -4514,115 +4514,403 @@
 ver(
-(i, j, k) -%3E %7B%0A                        Server server = new Server();%0A                        return server;
+new JettyServerFactory() %7B%0A                        @Override%0A                        public Server create(int i, int i1, int i2) %7B%0A                            return new Server();%0A                        %7D%0A%0A                        @Override%0A                        public Server create(ThreadPool threadPool) %7B%0A                            return new Server(threadPool);%0A                        %7D
 %0A   

Fix JettyServerFactory signature change for newer Spark