import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.restlet.Application;
import org.restlet.Component;
import org.springframework.beans.BeansException;
import org.springframework.web.servlet.FrameworkServlet;

import com.noelios.restlet.ext.servlet.ServletCall;
import com.noelios.restlet.http.HttpServerHelper;

public class RestletSpringBridgeServlet extends FrameworkServlet {

	/**
	 * Well-known name for the Restlet HttpServerHelper object in the bean
	 * factory for this namespace.
	 */
	public static final String HTTP_SERVER_HELPER_BEAN_NAME = "restletHttpServerHelper";

	/**
	 * Well-known name for the Restlet Application object in the bean factory
	 * for this namespace.
	 */
	public static final String APPLICATION_BEAN_NAME = "restletApplication";

	/**
	 * Well-known name for the Restlet component object in the bean factory for
	 * this namespace.
	 */
	private static final String COMPONENT_BEAN_NAME = "restletComponent";

	/** Serial version identifier. */
	private static final long serialVersionUID = 1L;

	/** The associated Restlet application. */
	private transient Application application;

	/** The associated Restlet component. */
	private transient Component component;

	/** The associated HTTP server helper. */
	private transient HttpServerHelper helper;

	/**
	 * Constructor.
	 */
	public RestletSpringBridgeServlet() {
		this.application = null;
		this.component = null;
		this.helper = null;
	}

	private void attachApplication(HttpServletRequest request,
			HttpServerHelper helper) {
		Component component = getComponent();
		Application application = getApplication();
		// Attach the application
		String uriPattern = request.getContextPath() + request.getServletPath();
		component.getDefaultHost().attach(uriPattern, application);
	}

	@Override
	public void destroy() {
		if ((getApplication() != null) && (getApplication().isStarted())) {
			try {
				getApplication().stop();
			} catch (Exception e) {
				log("Error during the stopping of the Restlet Application", e);
			}
		}

		super.destroy();
	}

	/**
	 * 
	 */
	@Override
	protected void doService(HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		HttpServerHelper helper = getServerHelper(request);
		// HttpServerHelper helper = getServer(request);
		if (helper != null) {
			helper
					.handle(new ServletCall(helper.getServer(), request,
							response));
		} else {
			log("[Restlet-Spring Bridge] - Unable to get the Restlet HTTP server connector. Status code 500 returned.");
			response.sendError(500);
		}

	}

	public Application getApplication() {
		Application result = this.application;

		if (result == null) {
			result = (Application) getWebApplicationContext().getBean(
					APPLICATION_BEAN_NAME, Application.class);
			this.application = result;
		}

		return result;
	}

	public Component getComponent() {
		Component result = this.component;

		if (result == null) {
			result = (Component) getWebApplicationContext().getBean(
					COMPONENT_BEAN_NAME, Component.class);

			this.component = result;

		}

		return result;
	}

	private HttpServerHelper getServerHelper(HttpServletRequest request) {
		HttpServerHelper result = this.helper;

		if (result == null) {
			result = (HttpServerHelper) getWebApplicationContext().getBean(
					HTTP_SERVER_HELPER_BEAN_NAME, HttpServerHelper.class);
			attachApplication(request, result);

			this.helper = result;
		}

		return result;
	}

	@Override
	protected void initFrameworkServlet() throws ServletException,
			BeansException {

		super.initFrameworkServlet();

		// get restlet application and start it
		if ((getApplication() != null) && (getApplication().isStopped())) {
			try {
				getApplication().start();
			} catch (Exception e) {
				log("Error during the starting of the Restlet Application", e);
			}
		}
	}

}
