package me.myapp.web.services.rest;

import java.io.IOException;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.restlet.Application;
import org.restlet.Request;
import org.restlet.Response;
import org.restlet.Restlet;
import org.restlet.ext.spring.SpringBeanFinder;
import org.restlet.ext.spring.SpringContext;
import org.restlet.resource.ServerResource;
import org.restlet.routing.Router;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.core.io.ClassPathResource;

/**
 * A Restlet {@link Application} subclass who load each resources and link they 
 * to the router considering there Spring "name" attributes.
 * <p>This class in based on the work of Irfan Jamadar (
 * <a href="http://wiki.restlet.org/community/164-restlet.html">
 * http://wiki.restlet.org/community/164-restlet.html</a>).</p>
 * 
 * @version 1.0
 */
public class RestApplication extends Application {

	public static void main(String[] args) {
		try {
			Component component = new Component();			
			component.getServers().add(Protocol.HTTP, 8081);
			//component.getClients().add(Protocol.FILE);
			
			Application application = new RestApplication();
			component.getDefaultHost().attach(application);		
			component.start();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	// ~ ------------------------------------------------------------------ ~ //


	private final static Logger logger = Logger.getLogger(RestApplication.class.getName());
	
	private final static String PROPERTIES_PLACEHOLDER = "config.properties";
	private final static String CONTEXT_CONFIG_FILE    = "webServiceContext.xml";
	
	static {
		/* Install the SLF4J bridge who redirect each Java standard logger 
		 * call to the Log4j logger. */
		//SLF4JBridgeHandler.install();
	}
		
	public RestApplication(){ /* Nothing */ }
	

	@Override
	public Restlet createInboundRoot() {
		Properties properties = new Properties();
		try {
			properties.load(getClass().getClassLoader()
					.getResourceAsStream(PROPERTIES_PLACEHOLDER));			
		} catch (IOException e) {
			logger.log(Level.SEVERE, "Unable to load properties placeholde "+
					PROPERTIES_PLACEHOLDER+".", e);
		}		
	
		SpringContext springContext = new SpringContext(getContext());
		XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(springContext);		
		xmlReader.loadBeanDefinitions(new ClassPathResource(CONTEXT_CONFIG_FILE));
	
		PropertyPlaceholderConfigurer config = new PropertyPlaceholderConfigurer();
		config.setProperties(properties);
		config.postProcessBeanFactory(springContext.getBeanFactory());
		
		Router router = (Router) springContext.getBean("router");
		for( String name : springContext.getBeanNamesForType(ServerResource.class)) {
			String[] aliases = springContext.getAliases(name);
			for (int i=0; i<aliases.length; i++ ) {
				if ( aliases[i].charAt(0)=='/' ) {
					logger.log(Level.INFO, "Resource "+name+" ("+
							springContext.getType(name)+") attached for path "+aliases[i]+".");
					router.attach(aliases[i], 
							new CustomSpringBeanFinder(springContext, name));
				}
			}
		}
		return router;
	}
	

	@Override
	public void handle(Request request, Response response) {
		try {
			start();			
		} catch (Exception ee) {
			ee.printStackTrace();
		}
		super.handle(request, response);
	}
	
	
	// ~ Internal classes ------------------------------------------------------
	
	private class CustomSpringBeanFinder extends SpringBeanFinder {
		
		public CustomSpringBeanFinder(BeanFactory beanFactory, String beanName) {
			super(beanFactory, beanName);
		}
				
		@Override
		public Class<?> getTargetClass() {
			return getBeanFactory().getType(getBeanName());
		}
		
		@Override
		public ServerResource create(Class<? extends ServerResource> targetClass, 
				Request request, Response response) {
			ServerResource result = (ServerResource) 
				getBeanFactory().getBean(getBeanName(), ServerResource.class);
			return result;
		}		
	}

}
