/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.apache.wicket.request.mapper.mount;

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.mapper.AbstractMapper;
import org.apache.wicket.util.lang.Args;
import org.apache.wicket.util.string.StringValue;

/**
 * {@link IRequestMapper} that can mount requests onto urls. TODO docs and unit test
 * 
 * @author igor.vaynberg
 */
public class MountMapper extends AbstractMapper
{
	private final String[] mountSegments;
	private final IMountedRequestMapper mapper;

	/**
	 * Construct.
	 * 
	 * @param mountPath
	 * @param mapper
	 */
	public MountMapper(String mountPath, IMountedRequestMapper mapper)
	{
		Args.notEmpty(mountPath, "mountPath");
		Args.notNull(mapper, "mapper");

		mountSegments = getMountSegments(mountPath);
		this.mapper = mapper;
	}

	/**
	 * Construct.
	 * 
	 * @param mountPath
	 * @param mapper
	 */
	public MountMapper(String mountPath, IRequestMapper mapper)
	{
		Args.notEmpty(mountPath, "mountPath");
		Args.notNull(mapper, "mapper");

		mountSegments = getMountSegments(mountPath);
		this.mapper = new UnmountedMapperAdapter(mapper);
	}

	/**
	 * Construct.
	 * 
	 * @param mountPath
	 * @param handler
	 */
	public MountMapper(String mountPath, IRequestHandler handler)
	{
		Args.notEmpty(mountPath, "mountPath");
		Args.notNull(handler, "handler");

		mountSegments = getMountSegments(mountPath);
		mapper = new UnmountedRequestHandlerAdapter(handler);
	}

	/**
	 * @see org.apache.wicket.request.IRequestMapper#getCompatibilityScore(org.apache.wicket.request.Request)
	 */
	public int getCompatibilityScore(Request request)
	{
		if (urlStartsWith(request.getUrl(), mountSegments))
		{
			return mountSegments.length + mapper.getCompatibilityScore(dismountRequest(request));
		}
		else
		{
			return 0;
		}
	}

	/**
	 * 
	 * @param request
	 * @return
	 */
	private Request dismountRequest(Request request)
	{
		Url dismountedUrl = new Url(request.getUrl());
		dismountedUrl.removeLeadingSegments(mountSegments.length);
		return request.cloneWithUrl(dismountedUrl);
	}

	/**
	 * @see org.apache.wicket.request.IRequestMapper#mapRequest(org.apache.wicket.request.Request)
	 */
	public final IRequestHandler mapRequest(Request request)
	{
		final Url url = request.getUrl();

		if (url.getSegments().size() >= mountSegments.length && urlStartsWith(url, mountSegments))
		{
			MountParameters params = new MountParameters();
			for (int i = 0; i < mountSegments.length; i++)
			{
				String placeholder = getPlaceholder(mountSegments[i]);
				if (placeholder != null)
				{
					params.setValue(placeholder, StringValue.valueOf(url.getSegments().get(i)));
				}
			}

			return mapper.mapRequest(dismountRequest(request), params);
		}

		return null;
	}

	/**
	 * @see org.apache.wicket.request.IRequestMapper#mapHandler(org.apache.org.apache.wicket.request.IRequestHandler)
	 */
	public Url mapHandler(IRequestHandler handler)
	{
		Mount mount = mapper.mapHandler(handler);
		if (mount == null)
		{
			return null;
		}

		// TODO
		// Check.notNull(mount.getUrl());
		// Check.notNull(mount.getMountParameters());

		for (int i = mountSegments.length; i > 0; i--)
		{
			String segment = mountSegments[i - 1];
			String placeholder = getPlaceholder(segment);
			String replacement = segment;

			if (placeholder != null)
			{
				replacement = mount.getMountParameters().getValue(placeholder).toString();
				if (replacement == null)
				{
					throw new IllegalStateException();// TODO message
				}
			}

			mount.getUrl().getSegments().add(0, replacement);
		}

		return mount.getUrl();
	}
}

@@ -1145,16 +1145,60 @@
 .Args;%0D%0A
+import org.apache.wicket.util.lang.Checks;%0D%0A
 import o
@@ -1240,16 +1240,16 @@
 Value;%0D%0A
-
 %0D%0A/**%0D%0A 
@@ -2887,15 +2887,206 @@
 %09 * 
-@return
+           a %7B@link Request%7D with the all mount segments - mount ones and the ones for the%0D%0A%09 *            delegated mapper%0D%0A%09 * @return a %7B@link Request%7D with %7B@link Url%7D without the mount segments
 %0D%0A%09 
@@ -4299,27 +4299,14 @@
 %0D%0A%09%09
-// TODO%0D%0A%09%09// 
 Check
+s
 .not
@@ -4328,22 +4328,54 @@
 rl()
+, %22Mount's Url should not be null%22
 );%0D%0A%09%09
-// 
 Check
+s
 .not
@@ -4405,16 +4405,57 @@
 meters()
+, %22Mount's parameters should not be null%22
 );%0D%0A%0D%0A%09%09
@@ -4829,25 +4829,89 @@
 ion(
-);// TODO message
+String.format(%0D%0A%09%09%09%09%09%09%22Cannot find a value for placeholder '%25s'.%22, placeholder));
 %0D%0A%09%09

Add documentation and exception messages