Index: /trunk/src/org/openstreetmap/josm/io/remotecontrol/RequestProcessor.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/io/remotecontrol/RequestProcessor.java	(revision 6090)
+++ /trunk/src/org/openstreetmap/josm/io/remotecontrol/RequestProcessor.java	(revision 6091)
@@ -8,4 +8,6 @@
 import java.io.OutputStream;
 import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.StringWriter;
 import java.io.Writer;
 import java.net.Socket;
@@ -17,4 +19,6 @@
 import java.util.StringTokenizer;
 import java.util.TreeMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -22,4 +26,5 @@
 import org.openstreetmap.josm.io.remotecontrol.handler.AddNodeHandler;
 import org.openstreetmap.josm.io.remotecontrol.handler.AddWayHandler;
+import org.openstreetmap.josm.io.remotecontrol.handler.FeaturesHandler;
 import org.openstreetmap.josm.io.remotecontrol.handler.ImageryHandler;
 import org.openstreetmap.josm.io.remotecontrol.handler.ImportHandler;
@@ -127,4 +132,5 @@
         addRequestHandlerClass(LoadObjectHandler.command, LoadObjectHandler.class, true);
         addRequestHandlerClass(OpenFileHandler.command, OpenFileHandler.class, true);
+        addRequestHandlerClass(FeaturesHandler.command, FeaturesHandler.class, true);
     }
 
@@ -204,15 +210,5 @@
             Class<? extends RequestHandler> handlerClass = handlers.get(command);
             if (handlerClass == null) {
-                // no handler found
-                StringBuilder usage = new StringBuilder(1024);
-                for (Entry<String, Class<? extends RequestHandler>> handler : handlers.entrySet()) {
-                    String[] mandatory = handler.getValue().newInstance().getMandatoryParams();
-                    usage.append("<li>");
-                    usage.append(handler.getKey());
-                    if (mandatory != null) {
-                        usage.append("<br/>mandatory parameter: ").append(Utils.join(", ", Arrays.asList(mandatory)));
-                    }
-                    usage.append("</li>");
-                }
+                String usage = getUsageAsHtml();
                 String websiteDoc = "http://josm.openstreetmap.de/wiki/Help/Preferences/RemoteControl";
                 String help = "No command specified! The following commands are available:<ul>"
@@ -365,3 +361,119 @@
             out.write("\r\n");
     }
+    
+    public static String getHandlersInfoAsJSON() {
+        StringBuilder r = new StringBuilder();
+        boolean first = true;
+        r.append("[");
+        
+        for (Entry<String, Class<? extends RequestHandler>> p : handlers.entrySet()) {
+            if (first) {
+                first = false;
+            } else {
+                r.append(", ");
+            }
+            r.append(getHanldlerInfoAsJSON(p.getKey()));
+        }
+        r.append("]");
+
+        return r.toString();
+    }
+
+    public static String getHanldlerInfoAsJSON(String cmd) {
+        StringWriter w = new StringWriter();
+        PrintWriter r = new PrintWriter(w);
+        RequestHandler handler = null;
+        try {
+            Class c = handlers.get(cmd);
+            if (c==null) return null;
+            handler = handlers.get(cmd).newInstance();
+        } catch (Exception ex) {
+            ex.printStackTrace();
+            return null;
+        }
+        if (handler==null) return null;
+
+        r.printf("{ \"request\" : \"%s\"", cmd);
+        r.append(", \"parameters\" : [");
+
+        String params[] = handler.getMandatoryParams();
+        if (params != null) {
+            for (int i = 0; i < params.length; i++) {
+                if (i == 0) {
+                    r.append('\"');
+                } else {
+                    r.append(", \"");
+                }
+                r.append(params[i]).append('\"');
+            }
+        }
+        r.append("], \"optional\" : [");
+        String optional[] = handler.getOptionalParams();
+        if (optional != null) {
+            for (int i = 0; i < optional.length; i++) {
+                if (i == 0) {
+                    r.append('\"');
+                } else {
+                    r.append(", \"");
+                }
+                r.append(optional[i]).append('\"');
+            }
+        }
+        
+        r.append("], \"examples\" : [");
+        String examples[] = handler.getUsageExamples();
+        if (examples != null) {
+            for (int i = 0; i < examples.length; i++) {
+                if (i == 0) {
+                    r.append('\"');
+                } else {
+                    r.append(", \"");
+                }
+                r.append(examples[i]).append('\"');
+            }
+        }
+        r.append("]}");
+        try {
+            return w.toString();
+        } finally {
+            try {
+                w.close();
+            } catch (IOException ex) {
+            }
+        }
+    }
+
+
+    /**
+     * Reports HTML message with the description of all available commands
+     * @return
+     * @throws IllegalAccessException
+     * @throws InstantiationException 
+     */
+    public static String getUsageAsHtml() throws IllegalAccessException, InstantiationException {
+        // no handler found
+        StringBuilder usage = new StringBuilder(1024);
+        for (Entry<String, Class<? extends RequestHandler>> handler : handlers.entrySet()) {
+            RequestHandler sample = handler.getValue().newInstance();
+            String[] mandatory = sample.getMandatoryParams();
+            String[] optional = sample.getOptionalParams();
+            String[] examples = sample.getUsageExamples();
+            usage.append("<li>");
+            usage.append(handler.getKey());
+            if (mandatory != null) {
+                usage.append("<br/>mandatory parameters: ").append(Utils.join(", ", Arrays.asList(mandatory)));
+            }
+            if (optional != null) {
+                usage.append("<br/>optional parameters: ").append(Utils.join(", ", Arrays.asList(optional)));
+            }
+            if (examples != null) {
+                usage.append("<br/>examples: ");
+                for (String ex: examples) {
+                    usage.append("<br/> <a href=\"http://localhost:8111"+ex+"\">"+ex+"</a>");
+                }
+            }
+            usage.append("</li>");
+        }
+        return usage.toString();
+    }
 }
Index: /trunk/src/org/openstreetmap/josm/io/remotecontrol/handler/AddNodeHandler.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/io/remotecontrol/handler/AddNodeHandler.java	(revision 6090)
+++ /trunk/src/org/openstreetmap/josm/io/remotecontrol/handler/AddNodeHandler.java	(revision 6091)
@@ -44,5 +44,19 @@
         return new String[] { "lat", "lon" };
     }
+    
+    @Override
+    public String[] getOptionalParams()
+    {
+        return new String[] { "addtags" };
+    }
 
+    @Override
+    public String[] getUsageExamples() {
+        return new String[] {
+            "/add_node?lat=11&lon=22",
+            "/add_node?lon=13.3&lat=53.2&addtags=natural=tree|name=%20%20%20==Great%20Oak==" 
+        };
+    }
+    
     @Override
     public String getPermissionMessage() {
Index: /trunk/src/org/openstreetmap/josm/io/remotecontrol/handler/AddWayHandler.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/io/remotecontrol/handler/AddWayHandler.java	(revision 6090)
+++ /trunk/src/org/openstreetmap/josm/io/remotecontrol/handler/AddWayHandler.java	(revision 6091)
@@ -46,5 +46,18 @@
         return new String[]{"way"};
     }
+    
+    @Override
+    public String[] getOptionalParams() {
+        return new String[] { "addtags" };
+    }
 
+    @Override
+    public String[] getUsageExamples() {
+        return new String[] {
+            "/add_way?way=53.2,13.3;53.3,13.3;53.3,13.2",
+            "/add_way?&addtags=building=yes&way=45.437213,-2.810792;45.437988,-2.455983;45.224080,-2.455036;45.223302,-2.809845;45.437213,-2.810792"
+        };
+    }
+    
     @Override
     protected void handleRequest() throws RequestHandlerErrorException, RequestHandlerBadRequestException {
Index: /trunk/src/org/openstreetmap/josm/io/remotecontrol/handler/FeaturesHandler.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/io/remotecontrol/handler/FeaturesHandler.java	(revision 6091)
+++ /trunk/src/org/openstreetmap/josm/io/remotecontrol/handler/FeaturesHandler.java	(revision 6091)
@@ -0,0 +1,83 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.io.remotecontrol.handler;
+
+import org.openstreetmap.josm.Main;
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import org.openstreetmap.josm.io.remotecontrol.PermissionPrefWithDefault;
+import org.openstreetmap.josm.io.remotecontrol.RequestProcessor;
+
+/**
+ * Reports avalable commands, their parameters and examples
+ * @since 6091
+ */
+public class FeaturesHandler extends RequestHandler {
+
+    /**
+     * The remote control command name used to reply version.
+     */
+    public static final String command = "features";
+
+    @Override
+    protected void handleRequest() throws RequestHandlerErrorException,
+            RequestHandlerBadRequestException {
+        StringBuilder buf = new StringBuilder();
+        String q=args.get("q");
+        if (q!=null) {
+            buf.append("[");
+            boolean first = true;
+            for (String s: q.split("[,\\s]+")) {
+               if (first) {
+                   first = false;
+               } else {
+                   buf.append(", ");
+               }
+               String info = RequestProcessor.getHanldlerInfoAsJSON("/"+s);
+               if (info!=null) {
+                   buf.append(info);
+               } else {
+                   Main.warn("Unknown handler {0} passed to /features request", s);
+               }
+            }
+            buf.append("]");
+        } else {
+            buf.append(RequestProcessor.getHandlersInfoAsJSON());
+        }
+            
+        content = buf.toString();
+        contentType = "application/json";
+        if (args.containsKey("jsonp")) {
+            content = args.get("jsonp") + " && " + args.get("jsonp") + "(" + content + ")";
+        }
+    }
+
+    @Override
+    public String getPermissionMessage() {
+        return tr("Remote Control has been asked to report its supported features. This enables web sites to guess a running JOSM version");
+    }
+
+    @Override
+    public PermissionPrefWithDefault getPermissionPref() {
+        return PermissionPrefWithDefault.READ_PROTOCOL_VERSION;
+    }
+
+    @Override
+    public String[] getMandatoryParams() {
+        return null;
+    }
+    
+    @Override
+    public String[] getOptionalParams() {
+        return new String[]{"jsonp", "q"};
+    }
+
+    @Override
+    protected void validateRequest() throws RequestHandlerBadRequestException {
+        // Nothing to do
+    }
+
+    @Override
+    public String[] getUsageExamples() {
+        return new String[] {"/features", "/features?q=import,add_node"}; 
+    }
+}
Index: /trunk/src/org/openstreetmap/josm/io/remotecontrol/handler/ImageryHandler.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/io/remotecontrol/handler/ImageryHandler.java	(revision 6090)
+++ /trunk/src/org/openstreetmap/josm/io/remotecontrol/handler/ImageryHandler.java	(revision 6091)
@@ -2,4 +2,5 @@
 package org.openstreetmap.josm.io.remotecontrol.handler;
 
+import java.util.Arrays;
 import static org.openstreetmap.josm.tools.I18n.tr;
 
@@ -11,4 +12,5 @@
 import org.openstreetmap.josm.gui.util.GuiHelper;
 import org.openstreetmap.josm.io.remotecontrol.PermissionPrefWithDefault;
+import org.openstreetmap.josm.tools.Utils;
 
 /**
@@ -32,4 +34,9 @@
     public String[] getMandatoryParams() {
         return new String[]{"url"};
+    }
+    
+    @Override
+    public String[] getOptionalParams() {
+        return new String[] { "title", "type", "cookies", "min_zoom", "max_zoom"};
     }
 
@@ -100,8 +107,21 @@
         this.args = args;
     }
-
+    
     @Override
     protected void validateRequest() throws RequestHandlerBadRequestException {
         // Nothing to do
     }
+
+    @Override
+    public String[] getUsageExamples() {
+        final String types = Utils.join("|", Utils.transform(Arrays.asList(ImageryInfo.ImageryType.values()), new Utils.Function<ImageryInfo.ImageryType, String>() {
+            @Override
+            public String apply(ImageryInfo.ImageryType x) {
+                return x.getUrlString();
+            }
+        }));
+        return new String[] { "/imagery?title=osm&type=tms&url=http://tile.openstreetmap.org/%7Bzoom%7D/%7Bx%7D/%7By%7D.png",
+            "/imagery?title=landsat&type=wms&url=http://irs.gis-lab.info/?layers=landsat&SRS=%7Bproj%7D&WIDTH=%7Bwidth%7D&HEIGHT=%7Bheight%7D&BBOX=%7Bbbox%7D",
+            "/imagery?title=...&type={"+types+"}&url=....[&cookies=...][&min_zoom=...][&max_zoom=...]"};
+    }
 }
Index: /trunk/src/org/openstreetmap/josm/io/remotecontrol/handler/ImportHandler.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/io/remotecontrol/handler/ImportHandler.java	(revision 6090)
+++ /trunk/src/org/openstreetmap/josm/io/remotecontrol/handler/ImportHandler.java	(revision 6091)
@@ -45,5 +45,15 @@
         return new String[]{"url"};
     }
+    
+    @Override
+    public String[] getOptionalParams() {
+        return new String[] {"new_layer"};
+    }
 
+    @Override
+    public String[] getUsageExamples() {
+        return new String[] { "/import?urlhttp://josm.openstreetmap.de/browser/josm/trunk/data_nodist/direction-arrows.osm" };
+    }
+    
     @Override
     public String getPermissionMessage() {
Index: /trunk/src/org/openstreetmap/josm/io/remotecontrol/handler/LoadAndZoomHandler.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/io/remotecontrol/handler/LoadAndZoomHandler.java	(revision 6090)
+++ /trunk/src/org/openstreetmap/josm/io/remotecontrol/handler/LoadAndZoomHandler.java	(revision 6091)
@@ -73,4 +73,22 @@
 
     @Override
+    public String[] getOptionalParams()
+    {
+        return new String[] {"new_layer", "addtags", "select", "zoom_mode"};
+    }
+
+    @Override
+    public String[] getUsageExamples() {
+        if (command.equals(myCommand)) {
+            return new String[] { 
+                "/load_and_zoom?addtags=wikipedia:de=Wei%C3%9Fe_Gasse|maxspeed=5&select=way23071688,way23076176,way23076177,&left=13.740&right=13.741&top=51.05&bottom=51.049",
+                "/load_and_zoom?left=8.19&right=8.20&top=48.605&bottom=48.590&select=node413602999&new_layer=true"};
+        } else {
+            return new String[] { 
+                "/zoom?left=8.19&right=8.20&top=48.605&bottom=48.590&select=node413602999"};
+        }
+    }
+    
+    @Override
     protected void handleRequest() throws RequestHandlerErrorException
     {
Index: /trunk/src/org/openstreetmap/josm/io/remotecontrol/handler/LoadObjectHandler.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/io/remotecontrol/handler/LoadObjectHandler.java	(revision 6090)
+++ /trunk/src/org/openstreetmap/josm/io/remotecontrol/handler/LoadObjectHandler.java	(revision 6091)
@@ -32,4 +32,17 @@
     public String[] getMandatoryParams() {
         return new String[]{"objects"};
+    }
+    
+    @Override
+    public String[] getOptionalParams()
+    {
+        return new String[] {"new_layer", "addtags"};
+    }
+
+    @Override
+    public String[] getUsageExamples() {
+        return new String[] {"/load_object?new_layer=true&objects=w106159509",
+            "/load_object?new_layer=true&objects=r2263653&relation_members=true"
+        };
     }
 
Index: /trunk/src/org/openstreetmap/josm/io/remotecontrol/handler/OpenFileHandler.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/io/remotecontrol/handler/OpenFileHandler.java	(revision 6090)
+++ /trunk/src/org/openstreetmap/josm/io/remotecontrol/handler/OpenFileHandler.java	(revision 6091)
@@ -25,4 +25,14 @@
         return new String[]{"filename"};
     }
+    
+    @Override
+    public String[] getOptionalParams() {
+        return null;
+    }
+
+    @Override
+    public String[] getUsageExamples() {
+        return new String[] {"/open_file?filename=/tmp/test.osm"};
+    }
 
     @Override
Index: /trunk/src/org/openstreetmap/josm/io/remotecontrol/handler/RequestHandler.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/io/remotecontrol/handler/RequestHandler.java	(revision 6090)
+++ /trunk/src/org/openstreetmap/josm/io/remotecontrol/handler/RequestHandler.java	(revision 6091)
@@ -7,5 +7,7 @@
 import java.net.URLDecoder;
 import java.text.MessageFormat;
+import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
@@ -106,4 +108,12 @@
 
     abstract public String[] getMandatoryParams();
+    
+    public String[] getOptionalParams() {
+        return null;
+    }
+     
+    public String[] getUsageExamples() {
+        return null;
+    }
 
     /**
@@ -176,6 +186,6 @@
                 String query = req.substring(req.indexOf('?') + 1);
                 if (query.indexOf('#') != -1) {
-                    query = query.substring(0, query.indexOf('#'));
-                }
+                            query = query.substring(0, query.indexOf('#'));
+                        }
                 String[] params = query.split("&", -1);
                 for (String param : params) {
@@ -194,9 +204,8 @@
     void checkMandatoryParams() throws RequestHandlerBadRequestException {
         String[] mandatory = getMandatoryParams();
-        if(mandatory == null) return;
-
+        String[] optional = getOptionalParams();
         List<String> missingKeys = new LinkedList<String>();
         boolean error = false;
-        for (String key : mandatory) {
+        if(mandatory != null) for (String key : mandatory) {
             String value = args.get(key);
             if ((value == null) || (value.length() == 0)) {
@@ -206,4 +215,12 @@
             }
         }
+        HashSet<String> knownParams = new HashSet<String>();
+        if (mandatory != null) Collections.addAll(knownParams, mandatory);
+        if (optional != null) Collections.addAll(knownParams, optional);
+        for (String par: args.keySet()) {
+            if (!knownParams.contains(par)) {
+                Main.warn("Unknown remote control parameter {0}, skipping it", par);
+            }
+        }
         if (error) {
             throw new RequestHandlerBadRequestException(
@@ -211,4 +228,5 @@
                     + Utils.join(", ", missingKeys));
         }
+        
     }
 
Index: /trunk/src/org/openstreetmap/josm/io/remotecontrol/handler/VersionHandler.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/io/remotecontrol/handler/VersionHandler.java	(revision 6090)
+++ /trunk/src/org/openstreetmap/josm/io/remotecontrol/handler/VersionHandler.java	(revision 6091)
@@ -43,6 +43,16 @@
 
     @Override
+    public String[] getOptionalParams() {
+        return new String[]{"jsonp"};
+    }
+
+    @Override
     protected void validateRequest() throws RequestHandlerBadRequestException {
         // Nothing to do
     }
+
+    @Override
+    public String[] getUsageExamples() {
+        return new String[] { "/version", "/version?jsonp=test"};
+    }
 }
