/** @see wicket.request.IRequestCodingStrategy#decode(wicket.Request) */
  public final RequestParameters decode(final Request request) {
    final RequestParameters parameters = new RequestParameters();
    String pathInfo = getRequestPath(request);
    if (pathInfo != null && !pathInfo.startsWith("/")) {
      pathInfo = "/" + pathInfo;
    }
    parameters.setPath(pathInfo);
    parameters.setPageMapName(request.getParameter(PAGEMAP));
    addInterfaceParameters(request, parameters);
    addBookmarkablePageParameters(request, parameters);
    addResourceParameters(request, parameters);

    parameters.setBehaviorId(request.getParameter(BEHAVIOR_ID_PARAMETER_NAME));

    Map<String, ? extends Object> map = request.getParameterMap();
    Iterator<String> iterator = map.keySet().iterator();
    while (iterator.hasNext()) {
      String key = iterator.next();
      if (key.startsWith(NAME_SPACE)) {
        iterator.remove();
      }
    }
    parameters.setParameters(map);
    return parameters;
  }
  /**
   * Adds bookmarkable page related parameters (page alias and optionally page parameters). Any
   * bookmarkable page alias mount will override this method; hence if a mount is found, this method
   * will not be called.
   *
   * <p>If you override this method to behave different then also {@link #encode(RequestCycle,
   * IBookmarkablePageRequestTarget)} should be overridden to by in sync with that behaviour.
   *
   * @param request the incoming request
   * @param parameters the parameters object to set the found values on
   */
  protected void addBookmarkablePageParameters(
      final Request request, final RequestParameters parameters) {
    final String requestString =
        request.getParameter(WebRequestCodingStrategy.BOOKMARKABLE_PAGE_PARAMETER_NAME);
    if (requestString != null) {
      final String[] components = Strings.split(requestString, Component.PATH_SEPARATOR);
      if (components.length != 2) {
        throw new WicketRuntimeException(
            "Invalid bookmarkablePage parameter: "
                + requestString
                + ", expected: 'pageMapName:pageClassName'");
      }

      // Extract any pagemap name
      final String pageMapName = components[0];
      parameters.setPageMapName(pageMapName.length() == 0 ? PageMap.DEFAULT_NAME : pageMapName);

      // Extract bookmarkable page class name
      final String pageClassName = components[1];
      parameters.setBookmarkablePageClass(pageClassName);
    }
  }
  /**
   * Adds page related parameters (path and pagemap and optionally version and interface).
   *
   * <p>If you override this method to behave different then also {@link #encode(RequestCycle,
   * IListenerInterfaceRequestTarget)} should be overridden to by in sync with that behaviour.
   *
   * @param request the incoming request
   * @param parameters the parameters object to set the found values on
   */
  protected void addInterfaceParameters(final Request request, final RequestParameters parameters) {
    // Format of interface target parameter is
    // <page-map-name>:<path>:<version>:<interface>
    final String requestString = request.getParameter(INTERFACE_PARAMETER_NAME);
    if (requestString != null) {
      // Split into array of strings
      String[] pathComponents = Strings.split(requestString, Component.PATH_SEPARATOR);

      // There must be at least 4 components
      if (pathComponents.length < 4) {
        throw new WicketRuntimeException(
            "Internal error parsing " + INTERFACE_PARAMETER_NAME + " = " + requestString);
      }

      // Set pagemap name
      final String pageMapName = pathComponents[0];
      parameters.setPageMapName(pageMapName.length() == 0 ? PageMap.DEFAULT_NAME : pageMapName);

      // Extract interface name after last colon
      final String interfaceName = pathComponents[pathComponents.length - 1];
      parameters.setInterfaceName(
          interfaceName.length() != 0 ? interfaceName : IRedirectListener.INTERFACE.getName());

      // Extract version
      final String versionNumberString = pathComponents[pathComponents.length - 2];
      final int versionNumber =
          Strings.isEmpty(versionNumberString) ? 0 : Integer.parseInt(versionNumberString);
      parameters.setVersionNumber(versionNumber);

      // Component path is everything after pageMapName and before version
      final int start = pageMapName.length() + 1;
      final int end =
          requestString.length() - interfaceName.length() - versionNumberString.length() - 2;
      final String componentPath = requestString.substring(start, end);
      parameters.setComponentPath(componentPath);
    }
  }