/********************************************************************
 * Copyright © 2004 VHA. All rights reserved
 ********************************************************************/
package gov.va.med.fw.ui.struts;

//java
import java.io.IOException;
//J2EE
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
//struts
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts.config.ModuleConfig;
import org.apache.struts.tiles.ComponentContext;
import org.apache.struts.tiles.Controller;
import org.apache.struts.tiles.ComponentDefinition;
import org.apache.struts.util.ModuleUtils;
//spring
import org.springframework.beans.BeansException;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.struts.ContextLoaderPlugIn;
//framework

/**
 * @author Madhu Katikala
 * controller interface is implemented to reuse the controller creation code
 * from struts
 */
public final class ServiceDelegatingTilesController implements Controller {
    protected static final Log log = LogFactory.getLog(ServiceDelegatingTilesController.class);
    
    //Empty constructor
    public ServiceDelegatingTilesController () {   
    }
    
	/* (non-Javadoc)
	 * @see org.apache.struts.tiles.Controller#execute(org.apache.struts.tiles.ComponentContext, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, javax.servlet.ServletContext)
     * Retrives the spring aware tiles controller bean from webapplicationcontext
     * and delegates the call.
	 */
	public void execute(ComponentContext tilesContext, HttpServletRequest request,
			HttpServletResponse response, ServletContext servletContext) throws Exception {
        
        //get the tiles component definition
        ComponentDefinition componentDefinition = 
            (ComponentDefinition)request.getAttribute(CustomTilesFactorySet.TILES_COMPONENT_DEFINITION);

        //Get Module Configuration
        ModuleConfig moduleConfig = ModuleUtils.getInstance().getModuleConfig(request);
        
        //get the instance of the controller
        AbstractTilesController controller = getDelegateTilesController(componentDefinition, moduleConfig, servletContext);
        //execute the controller method
        controller.execute(tilesContext, request, response, servletContext);
	}
    
	/* (non-Javadoc)
	 * @see org.apache.struts.tiles.Controller#perform(org.apache.struts.tiles.ComponentContext, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, javax.servlet.ServletContext)
     * Empty implementation of required methods for controller interface
     * As this is a deprecated in struts 1.1, should never be used in the future implementations
	 */
	public void perform(ComponentContext arg0, HttpServletRequest arg1,
			HttpServletResponse arg2, ServletContext arg3)
			throws ServletException, IOException {
	}
    
    /**
     * get the Bean Instance of TilesController from WebApplicationContext
     * @param componentDefinition the component definition
     * @param moduleConfig the module configuration
     * @param servletContext the servlet context
     * @return the abstract tiles controller
     * @throws BeansException
     */

    private AbstractTilesController getDelegateTilesController(
            ComponentDefinition componentDefinition, 
            ModuleConfig moduleConfig, 
            ServletContext servletContext)
    {
        //determine bean name for the tiles controller
        String beanName = moduleConfig.getPrefix() + componentDefinition.getName();
        if (log.isDebugEnabled()) {
            log.debug("DelegatingTilesController with mapping path '" +
                    componentDefinition.getPath() + 
                "' delegating to Spring bean with name [" + beanName + "]");
        }
        
        //Get webapp context from servlet context  
        //ContextLoaderPlugin is same across all modules try attribute in the default module        
        String attrName = ContextLoaderPlugIn.SERVLET_CONTEXT_PREFIX;
        WebApplicationContext wac = 
            (WebApplicationContext) servletContext.getAttribute(attrName);

        // If no context found, throw an exception.
        if (wac == null) {
            throw new IllegalStateException(
                "Could not find ContextLoaderPlugIn's WebApplicationContext in [" +
                "ServletContext] -Register " + ContextLoaderPlugIn.class.getName());
        }

        AbstractTilesController controller = 
            (AbstractTilesController) wac.getBean(beanName, 
                    AbstractTilesController.class);
        if (controller == null) {
            throw new IllegalStateException("Tiles Controller Not Found for name " + beanName);                     
        }
        return controller;
    }
}
