/**
 * Copyright 2011 55 Minutes (http://www.55minutes.com)
 *
 * 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 fiftyfive.wicket.resource;

import java.util.List;

import org.apache.wicket.request.IRequestHandler;
import org.apache.wicket.request.IRequestMapper;
import org.apache.wicket.request.Request;
import org.apache.wicket.request.Url;
import org.apache.wicket.request.handler.resource.ResourceReferenceRequestHandler;
import org.apache.wicket.request.mapper.AbstractMapper;
import org.apache.wicket.request.mapper.parameter.IPageParametersEncoder;
import org.apache.wicket.request.mapper.parameter.PageParameters;
import org.apache.wicket.request.resource.ResourceReference;
import org.apache.wicket.request.resource.caching.IResourceCachingStrategy;
import org.apache.wicket.request.resource.caching.ResourceUrl;
import org.apache.wicket.util.IProvider;
import org.apache.wicket.util.time.Time;


/**
 * Maps a single, static URL to a list of resources. When that URL is requested, respond by
 * merging all the resources together by delegating to {@link MergedResourceRequestHandler}.
 * 
 * @since 3.0
 */
public class MergedResourceMapper extends AbstractMapper implements IRequestMapper
{
    protected final String[] mountSegments;
    protected final List<ResourceReference> resources;
    protected final IPageParametersEncoder parametersEncoder;
    protected final IProvider<? extends IResourceCachingStrategy> cachingStrategy;
    
    public MergedResourceMapper(String path,
                                List<ResourceReference> resources,
                                IPageParametersEncoder parametersEncoder,
                                IProvider<? extends IResourceCachingStrategy> cachingStrategy)
    {
        // TODO: validate arguments
        this.resources = resources;
        this.mountSegments = getMountSegments(path);
        this.parametersEncoder = parametersEncoder;
        this.cachingStrategy = cachingStrategy;
    }
    
    public int getCompatibilityScore(Request request)
    {
        return 0;
    }
    
    public IRequestHandler mapRequest(Request request)
    {
        PageParameters parameters = null;
        List<String> requestSegments = request.getUrl().getSegments();
        
        if(requestSegments.size() < this.mountSegments.length)
        {
            return null;
        }
        for(int i=0; i<this.mountSegments.length; i++)
        {
            String segment = requestSegments.get(i);
            if(i+1 == this.mountSegments.length)
            {
                parameters = extractPageParameters(
                    request,
                    this.mountSegments.length,
                    this.parametersEncoder);
                
                ResourceUrl resourceUrl = new ResourceUrl(segment, parameters);
                this.cachingStrategy.get().undecorateUrl(resourceUrl);
                segment = resourceUrl.getFileName();
            }
            if(!segment.equals(this.mountSegments[i]))
            {
                return null;
            }
        }
        
        return new MergedResourceRequestHandler(
            this.resources,
            parameters,
            getLastModifiedReference().getLastModified());
    }

    public Url mapHandler(IRequestHandler requestHandler)
    {
        if(!(requestHandler instanceof ResourceReferenceRequestHandler)) return null;

        boolean matched = false;
        ResourceReferenceRequestHandler handler = (ResourceReferenceRequestHandler) requestHandler;
        for(ResourceReference ref : this.resources)
        {
            if(ref.equals(handler.getResourceReference()))
            {
                matched = true;
                break;
            }
        }
        
        if(!matched) return null;

        Url url = new Url();
        PageParameters parameters = new PageParameters(handler.getPageParameters());
        for(int i=0; i<this.mountSegments.length; i++)
        {
            String segment = mountSegments[i];
            if(i+1 == this.mountSegments.length)
            {
                segment = applyCachingStrategy(segment, parameters);
            }
            url.getSegments().add(segment);
        }
        
        return encodePageParameters(url, parameters, this.parametersEncoder);
    }
    
    protected String applyCachingStrategy(String fileName, PageParameters parameters)
    {
        ResourceUrl resourceUrl = new ResourceUrl(fileName, parameters);
        this.cachingStrategy.get().decorateUrl(resourceUrl, getLastModifiedReference());
        return resourceUrl.getFileName();
    }
    
    protected ResourceReference getLastModifiedReference()
    {
        ResourceReference lastModifiedRef = null;
        long lastMillis = -1;
        for(ResourceReference ref : this.resources)
        {
            Time refModified = ref.getLastModified();
            if(refModified != null && refModified.getMilliseconds() > lastMillis)
            {
                lastMillis = refModified.getMilliseconds();
                lastModifiedRef = ref;
            }
        }
        return lastModifiedRef != null ? lastModifiedRef : this.resources.get(0);
    }
}

@@ -850,24 +850,25 @@
 equest.Url;%0A
+%0A
 import org.a
@@ -930,32 +930,33 @@
 RequestHandler;%0A
+%0A
 import org.apach
@@ -1134,16 +1134,85 @@
 ameters;
+%0A%0Aimport org.apache.wicket.request.resource.PackageResourceReference;
 %0Aimport 
@@ -1341,16 +1341,16 @@
 rategy;%0A
-
 import o
@@ -1404,16 +1404,17 @@
 rceUrl;%0A
+%0A
 import o
@@ -5047,32 +5047,166 @@
 e, parameters);%0A
+        ResourceReference lastMod = getLastModifiedReference();%0A        if(lastMod instanceof PackageResourceReference)%0A        %7B%0A    
         this.cac
@@ -5253,36 +5253,54 @@
 rl, 
-getLastModifiedReference());
+(PackageResourceReference) lastMod);%0A        %7D
 %0A   

Fix compilation error introduced by recent changes in wicket trunk.