package org.wikiwebserver.core;

import java.net.BindException;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.ServerSocket;

import javax.net.ServerSocketFactory;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;

public class ServiceFactory {
    
    private static final int MAX_QUEUED_CONNECTIONS = ConfigManager.getInt("listener-max-queued-connections");
    
    public ClassLoader getHandlerClassLoader() throws MalformedURLException {
        ClassLoader parent = Thread.currentThread().getContextClassLoader();
        return new WikiClassLoader(WikiWebServer.getClassUrls(), parent);
    }   
    
    public static ConnectionListener createService( String name, 
										    		int port,
										    		String bindAddress,
										            String handlerClassName, 
										            String configurationClassName, 
										            boolean ssl ) {
        
        try {
        	InetAddress bindInetAddress = null;
        	if (bindAddress != null && bindAddress.trim().length() > 0) {
        		bindInetAddress = InetAddress.getByName(bindAddress.trim());
        	}
            ServerSocket ssock = null;
            if (ssl) {
                if (System.getProperty("javax.net.ssl.keyStore") == null) {
                    throw new BindException("No SSL keystore specified");
                }
                
                // Configure the SSL server socket used for listening for new connections
                ServerSocketFactory sslFactory = SSLServerSocketFactory.getDefault();
                SSLServerSocket sslHTTPServerSocket = (SSLServerSocket) 
                	sslFactory.createServerSocket(port,  MAX_QUEUED_CONNECTIONS, bindInetAddress);
                
                ssock = sslHTTPServerSocket;
            } 
            else {
                ssock = new ServerSocket(port, MAX_QUEUED_CONNECTIONS, bindInetAddress);
            }
            
            return new ConnectionListener(name, ssock, handlerClassName, configurationClassName);
            
        } 
        catch (SecurityException se) {
            // SecurityManager already set
            se.printStackTrace();
        } 
        catch (BindException ex) {
            // Network port in use
            System.err.println("Failed to create " + name + " service on port " + port + ".");
            ex.printStackTrace();
        } 
        catch (Exception ex) {
            ex.printStackTrace();
        }        
        
        return null;
    } 
    
    public static void startServices(ConnectionListener[] services) {
        for (ConnectionListener service : services) startService(service);
    }
    
    public static void startService(ConnectionListener service) {
        if (service != null) {
            Thread serviceThread = new Thread(service, service.getName() + " Connection Listener");
            serviceThread.start(); 
            System.out.println(service.getName() + " service started " + service.getAddress());
        }
    }    
}

