// Path: rsimulator-core/src/main/java/com/github/bjuvensjo/rsimulator/core/Simulator.java
// @ImplementedBy(SimulatorImpl.class)
// public interface Simulator {
// 
//     /**
//      * Returns a SimulatorResponse that matches the specified request.
//      *
//      * @param rootPath         the root path on which to search recursively for matches to the specified request
//      * @param rootRelativePath the path on which to search recursively for matches to the specified request
//      * @param request          the request
//      * @param contentType      the content type of the request, e.g. txt or xml
//      * @param vars             vars that can be used in for example scripts
//      * @return a SimulatorResponse that matches the specified request
//      */
//     Optional<SimulatorResponse> service(String rootPath, String rootRelativePath, String request, String contentType, Map<String, Object>... vars);
// }
// 
// Path: rsimulator-core/src/main/java/com/github/bjuvensjo/rsimulator/core/SimulatorResponse.java
// public interface SimulatorResponse {
// 
//     /**
//      * Returns the properties of a specific test data request and response pair. If the name of the test data request
//      * file for instance is Test1Request.xml, the properties file must be named Test1.properties. For supported
//      * properties, see *PropertiesInterceptor classes.
//      *
//      * @return the properties of a specific test data request and response pair
//      */
//     Optional<Properties> getProperties();
// 
//     /**
//      * Sets the specified properties.
//      *
//      * @param properties the properties to set
//      */
//     void setProperties(Optional<Properties> properties);
// 
//     /**
//      * Returns the test data response.
//      *
//      * @return the test data response
//      */
//     String getResponse();
// 
//     /**
//      * Sets the specified response.
//      *
//      * @param response the response to set
//      */
//     void setResponse(String response);
// 
//     /**
//      * Returns the matching request path.
//      *
//      * @return the matching request path
//      */
//     Path getMatchingRequest();
// 
//     /**
//      * Sets the specified path.
//      *
//      * @param path the path to set
//      */
//     void setMatchingRequest(Path path);
// }
// 
// Path: rsimulator-socket/src/main/java/com/github/bjuvensjo/rsimulator/socket/config/GlobalConfig.java
// public class GlobalConfig {
//     public static int port;
//     public static String rootPath;
//     public static boolean useRootRelativePath;
// 
//     static {
//         port = System.getProperty(Constants.PORT) != null ? Integer.parseInt(System
//                 .getProperty(Constants.PORT)) : Constants.DEFAULT_PORT;
// 
//         rootPath = System.getProperty(Constants.ROOT_PATH) != null ? System.getProperty(Constants.ROOT_PATH)
//                 : Constants.DEFAULT_ROOT_PATH;
// 
//         useRootRelativePath = System.getProperty(Constants.USE_ROOT_RELATIVE_PATH) != null && "true".equals(System
//                 .getProperty(Constants.USE_ROOT_RELATIVE_PATH));
//     }
// 
//     private GlobalConfig() {
//         // noop
//     }
// }


import com.github.bjuvensjo.rsimulator.core.Simulator;
import com.github.bjuvensjo.rsimulator.core.SimulatorResponse;
import com.github.bjuvensjo.rsimulator.socket.config.GlobalConfig;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.google.inject.name.Named;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Optional;
package com.github.bjuvensjo.rsimulator.socket;



/**
 * Manager
 */
@Singleton
public class Manager {

    @Inject
    private RequestReader requestReader;

    @Inject
    private ResponseWriter responseWriter;

    @Inject
    private Simulator simulator;

    @Inject
    @Named("simulatorContentType")
    private String simulatorContentType;

    public void handle(Socket s) throws IOException {
        Worker worker = new Worker(s);

        new Thread(worker).start();
    }

    class Worker implements Runnable {
        private final Logger log = LoggerFactory.getLogger(Worker.class);
        private final Socket s;

        public Worker(Socket s) throws IOException {
            this.s = s;
        }

        private RequestReader.Request read(InputStream in) throws IOException {
            return requestReader.read(in);
        }

// Path: rsimulator-core/src/main/java/com/github/bjuvensjo/rsimulator/core/Simulator.java
// @ImplementedBy(SimulatorImpl.class)
// public interface Simulator {
// 
//     /**
//      * Returns a SimulatorResponse that matches the specified request.
//      *
//      * @param rootPath         the root path on which to search recursively for matches to the specified request
//      * @param rootRelativePath the path on which to search recursively for matches to the specified request
//      * @param request          the request
//      * @param contentType      the content type of the request, e.g. txt or xml
//      * @param vars             vars that can be used in for example scripts
//      * @return a SimulatorResponse that matches the specified request
//      */
//     Optional<SimulatorResponse> service(String rootPath, String rootRelativePath, String request, String contentType, Map<String, Object>... vars);
// }
// 
// Path: rsimulator-core/src/main/java/com/github/bjuvensjo/rsimulator/core/SimulatorResponse.java
// public interface SimulatorResponse {
// 
//     /**
//      * Returns the properties of a specific test data request and response pair. If the name of the test data request
//      * file for instance is Test1Request.xml, the properties file must be named Test1.properties. For supported
//      * properties, see *PropertiesInterceptor classes.
//      *
//      * @return the properties of a specific test data request and response pair
//      */
//     Optional<Properties> getProperties();
// 
//     /**
//      * Sets the specified properties.
//      *
//      * @param properties the properties to set
//      */
//     void setProperties(Optional<Properties> properties);
// 
//     /**
//      * Returns the test data response.
//      *
//      * @return the test data response
//      */
//     String getResponse();
// 
//     /**
//      * Sets the specified response.
//      *
//      * @param response the response to set
//      */
//     void setResponse(String response);
// 
//     /**
//      * Returns the matching request path.
//      *
//      * @return the matching request path
//      */
//     Path getMatchingRequest();
// 
//     /**
//      * Sets the specified path.
//      *
//      * @param path the path to set
//      */
//     void setMatchingRequest(Path path);
// }
// 
// Path: rsimulator-socket/src/main/java/com/github/bjuvensjo/rsimulator/socket/config/GlobalConfig.java
// public class GlobalConfig {
//     public static int port;
//     public static String rootPath;
//     public static boolean useRootRelativePath;
// 
//     static {
//         port = System.getProperty(Constants.PORT) != null ? Integer.parseInt(System
//                 .getProperty(Constants.PORT)) : Constants.DEFAULT_PORT;
// 
//         rootPath = System.getProperty(Constants.ROOT_PATH) != null ? System.getProperty(Constants.ROOT_PATH)
//                 : Constants.DEFAULT_ROOT_PATH;
// 
//         useRootRelativePath = System.getProperty(Constants.USE_ROOT_RELATIVE_PATH) != null && "true".equals(System
//                 .getProperty(Constants.USE_ROOT_RELATIVE_PATH));
//     }
// 
//     private GlobalConfig() {
//         // noop
//     }
// }


// Path: rsimulator-socket/src/main/java/com/github/bjuvensjo/rsimulator/socket/Manager.java
import com.github.bjuvensjo.rsimulator.core.Simulator;
import com.github.bjuvensjo.rsimulator.core.SimulatorResponse;
import com.github.bjuvensjo.rsimulator.socket.config.GlobalConfig;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.google.inject.name.Named;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Optional;

package com.github.bjuvensjo.rsimulator.socket;



/**
 * Manager
 */
@Singleton
public class Manager {

    @Inject
    private RequestReader requestReader;

    @Inject
    private ResponseWriter responseWriter;

    @Inject
    private Simulator simulator;

    @Inject
    @Named("simulatorContentType")
    private String simulatorContentType;

    public void handle(Socket s) throws IOException {
        Worker worker = new Worker(s);

        new Thread(worker).start();
    }

    class Worker implements Runnable {
        private final Logger log = LoggerFactory.getLogger(Worker.class);
        private final Socket s;

        public Worker(Socket s) throws IOException {
            this.s = s;
        }

        private RequestReader.Request read(InputStream in) throws IOException {
            return requestReader.read(in);
        }

        private void write(RequestReader.Request request, SimulatorResponse simulatorResponse, OutputStream out) throws IOException {