/**
 * 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.PackageResourceReference;
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);
        ResourceReference lastMod = getLastModifiedReference();
        if(lastMod instanceof PackageResourceReference)
        {
            this.cachingStrategy.get().decorateUrl(resourceUrl, (PackageResourceReference) lastMod);
        }
        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);
    }
}

@@ -1178,38 +1178,23 @@
 esource.
-PackageResourceReferen
+IResour
 ce;%0Aimpo
@@ -1326,16 +1326,92 @@
 rategy;%0A
+import org.apache.wicket.request.resource.caching.IStaticCacheableResource;%0A
 import o
@@ -1503,24 +1503,80 @@
 .IProvider;%0A
+import org.apache.wicket.util.resource.IResourceStream;%0A
 import org.a
@@ -3906,20 +3906,13 @@
 fied
-Reference().
+Time(
 getL
@@ -3922,17 +3922,27 @@
 Modified
-(
+Reference()
 ));%0A    
@@ -5251,52 +5251,95 @@
     
-if(lastMod instanceof PackageResourceReferen
+IResource res = lastMod.getResource();%0A        if(res instanceof IStaticCacheableResour
 ce)%0A
@@ -5417,41 +5417,37 @@
 l, (
-PackageResourceReference) lastMod
+IStaticCacheableResource) res
 );%0A 
@@ -5746,20 +5746,16 @@
 ified = 
-ref.
 getLastM
@@ -5761,17 +5761,24 @@
 Modified
-(
+Time(ref
 );%0A     
@@ -6079,10 +6079,515 @@
 ;%0A    %7D%0A
+    %0A    /**%0A     * De-reference the resource and open its stream to determine the last modified time.%0A     */%0A    protected Time getLastModifiedTime(ResourceReference ref)%0A    %7B%0A        Time modified = null;%0A        IResource res = ref.getResource();%0A        if(res instanceof IStaticCacheableResource)%0A        %7B%0A            IResourceStream stream = ((IStaticCacheableResource) res).getCacheableResourceStream();%0A            modified = stream.lastModifiedTime();%0A        %7D%0A        return modified;%0A    %7D%0A
 %7D%0A

Update caching code to work with recent refactoring in Wicket trunk. See https://issues.apache.org/jira/browse/WICKET-3948