/* Copyright 2004-2005 Graeme Rocher
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.codehaus.groovy.grails.web.mapping.filter;

import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.UrlPathHelper;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.codehaus.groovy.grails.web.mapping.UrlMappingsHolder;
import org.codehaus.groovy.grails.web.mapping.UrlMapping;
import org.codehaus.groovy.grails.web.mapping.UrlMappingInfo;
import org.codehaus.groovy.grails.web.servlet.WrappedResponseHolder;
import org.codehaus.groovy.grails.web.servlet.GrailsUrlPathHelper;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.RequestDispatcher;
import java.io.IOException;

/**
 * <p>A Servlet filter that uses the Grails UrlMappings to match and forward requests to a relevant controller
 * and action
 *
 * @author Graeme Rocher
 * @since 0.5
 *
 *
 *        <p/>
 *        Created: Mar 6, 2007
 *        Time: 7:58:19 AM
 */
public class UrlMappingsFilter extends OncePerRequestFilter {

    private UrlPathHelper urlHelper = new UrlPathHelper();
    private static final String SLASH = "/";
    private static final Log LOG = LogFactory.getLog(UrlMappingsFilter.class);


    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        UrlMappingsHolder holder = lookupUrlMappings();

        if(LOG.isTraceEnabled()) {
            LOG.trace("Executing URL mapping filter");
        }
        
        UrlMapping[] mappings = holder.getUrlMappings();
        String uri = urlHelper.getPathWithinApplication(request);
        // filter doesn't apply to URLs with extensions for the moment, might add support
        // later to include certain extensions
        if(uri.substring(uri.lastIndexOf(SLASH)).indexOf(".") >-1) {
            filterChain.doFilter(request, response);
            return;
        }

        UrlMappingInfo info = null;
        for (int i = 0; i < mappings.length; i++) {

            UrlMapping mapping = mappings[i];
            if(LOG.isDebugEnabled())
                LOG.debug("Attempting to match URI ["+uri+"] with pattern ["+mapping.getUrlData().getUrlPattern()+"]");
            
            info = mapping.match(uri);

            if(info!=null) {
                break;
            }
        }

        if(info!=null) {
            String forwardUrl = buildDispatchUrlForMapping(request, info);
            if(LOG.isDebugEnabled()) {
                LOG.debug("Matched URI ["+uri+"] to URL mapping, forwarding to ["+forwardUrl+"] with response ["+response.getClass()+"]");
            }
            //populateParamsForMapping(info);
            RequestDispatcher dispatcher = request.getRequestDispatcher(forwardUrl);

            try {
                WrappedResponseHolder.setWrappedResponse(response);
                dispatcher.forward(request, response);                
            }
            finally {
                WrappedResponseHolder.setWrappedResponse(null);
            }



        }
        else {
            if(filterChain!=null)
                filterChain.doFilter(request, response);
        }
    }


    /**
     * Constructs the URI to forward to using the given request and UrlMappingInfo instance
     *
     * @param request The HttpServletRequest
     * @param info The UrlMappingInfo
     * @return The URI to forward to
     */
    protected String buildDispatchUrlForMapping(HttpServletRequest request, UrlMappingInfo info) {
        StringBuffer forwardUrl = new StringBuffer(GrailsUrlPathHelper.GRAILS_SERVLET_PATH);
        forwardUrl.append(SLASH)
                          .append(info.getControllerName());

        if(!StringUtils.isBlank(info.getActionName())) {
            forwardUrl.append(SLASH)
                      .append(info.getActionName());
        }
        forwardUrl.append(GrailsUrlPathHelper.GRAILS_DISPATCH_EXTENSION);
        return forwardUrl.toString();
    }

    /**
     * Looks up the UrlMappingsHolder instance
     *
     * @return The UrlMappingsHolder
     */
    protected UrlMappingsHolder lookupUrlMappings() {
        WebApplicationContext wac =
                WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());

        return (UrlMappingsHolder)wac.getBean(UrlMappingsHolder.BEAN_ID);
    }
}

@@ -1210,32 +1210,217 @@
 sUrlPathHelper;%0A
+import org.codehaus.groovy.grails.commons.GrailsApplication;%0Aimport org.codehaus.groovy.grails.commons.GrailsClass;%0Aimport org.codehaus.groovy.grails.commons.ControllerArtefactHandler;%0A
 import org.apach
@@ -1443,24 +1443,24 @@
 tringUtils;%0A
-
 import org.a
@@ -2483,16 +2483,315 @@
 pings();
+%0A        GrailsApplication application = lookupApplication();%0A%0A        GrailsClass%5B%5D controllers = application.getArtefacts(ControllerArtefactHandler.TYPE);%0A        if(controllers == null %7C%7C controllers.length == 0) %7B%0A            filterChain.doFilter(request,response);%0A            return;%0A        %7D
 %0A%0A      
@@ -4560,16 +4560,17 @@
     %7D%0A%0A%0A
+%0A
     /**%0A
@@ -5729,16 +5729,411 @@
 AN_ID);%0A
-
     %7D%0A
+%0A    /**%0A     * Looks up the GrailsApplication instance%0A     *%0A     * @return The GrailsApplication instance%0A     */%0A    protected GrailsApplication lookupApplication() %7B%0A        WebApplicationContext wac =%0A                WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());%0A%0A        return (GrailsApplication)wac.getBean(GrailsApplication.APPLICATION_ID);%0A%0A    %7D%0A%0A
 %7D%0A

fix for GRAILS-1153