Index: applications/editors/josm/plugins/waydownloader/build.xml
===================================================================
--- applications/editors/josm/plugins/waydownloader/build.xml	(revision 18601)
+++ applications/editors/josm/plugins/waydownloader/build.xml	(revision 18613)
@@ -22,4 +22,12 @@
 -->
 <project name="waydownloader" default="dist" basedir=".">
+	
+	<!-- 
+      ** update before publishing 
+	-->
+	<property name="commit.message" value="Fixed merging of nodes; improved messages; completed I18n; now uses referers and searching of nodes in a bounding box; now only enabled if current layer is a data layer; Updated build.xml" />		
+	<property name="plugin.main.version" value="2457" />
+	
+	
     <!--
       ************************************************
@@ -140,3 +148,81 @@
         <copy file="${plugin.jar}" todir="${josm.plugins.dir}"/>
     </target>
+	
+	
+	<!--
+		 ************************** Publishing the plugin *********************************** 
+		-->
+			<!--
+			  ** extracts the JOSM release for the JOSM version in ../core and saves it in the 
+			  ** property ${coreversion.info.entry.revision}
+			  **
+			-->
+			<target name="core-info">
+		        <exec append="false" output="core.info.xml" executable="svn" failifexecutionfails="false">
+		                    <env key="LANG" value="C"/>
+		                    <arg value="info"/>
+		                    <arg value="--xml"/>
+		                    <arg value="../../core"/>
+		        </exec>
+		        <xmlproperty file="core.info.xml" prefix="coreversion" keepRoot="true" collapseAttributes="true"/>
+				<echo>Building against core revision ${coreversion.info.entry.revision}.</echo>			
+				<echo>Plugin-Mainversion is set to ${plugin.main.version}.</echo>
+				<delete file="core.info.xml" />
+			</target>
+
+			<!--
+			 ** commits the source tree for this plugin
+			-->
+			<target name="commit-current">
+				<echo>Commiting the plugin source with message '${commit.message}' ...</echo>
+			    <exec append="true" output="svn.log" executable="svn" failifexecutionfails="false">
+			                    <env key="LANG" value="C"/>
+				                <arg value="-m '${commit.message}'"/>
+			    				<arg value="commit"/>
+			                    <arg value="."/>
+			    </exec>	    
+			</target>
+
+			<!--
+			** updates (svn up) the source tree for this plugin
+			-->
+			<target name="update-current">
+				<echo>Updating plugin source ...</echo>
+			    <exec append="true" output="svn.log" executable="svn" failifexecutionfails="false">
+			                    <env key="LANG" value="C"/>
+			                    <arg value="up"/>
+			                    <arg value="."/>
+			    </exec>	    
+				<echo>Updating ${plugin.jar} ...</echo>
+			    <exec append="true" output="svn.log" executable="svn" failifexecutionfails="false">
+			                    <env key="LANG" value="C"/>
+			                    <arg value="up"/>
+			                    <arg value="../dist/${plugin.jar}"/>
+			    </exec>	    
+			</target>
+			
+			<!--
+			 ** commits the plugin.jar 
+			 -->
+			<target name="commit-dist">
+					<echo>
+	***** Properties of published ${plugin.jar} *****
+	Commit message    : '${commit.message}'					
+	Plugin-Mainversion: ${plugin.main.version}
+	JOSM build version: ${coreversion.info.entry.revision}
+	Plugin-Version    : ${version.entry.commit.revision}
+	***** / Properties of published ${plugin.jar} *****					
+						
+	Now commiting ${plugin.jar} ...
+	</echo>					
+				    <exec append="true" output="svn.log" executable="svn" failifexecutionfails="false">
+				                    <env key="LANG" value="C"/>
+					    			<arg value="-m '${commit.message}'"/>
+				    				<arg value="commit"/>	                			
+	            			        <arg value="${plugin.jar}"/>
+				    </exec>	    
+		   	</target>
+					
+			<target name="publish" depends="core-info,commit-current,update-current,clean,dist,commit-dist">
+			</target>	
 </project>
Index: applications/editors/josm/plugins/waydownloader/src/org/openstreetmap/josm/plugins/waydownloader/WayDownloaderPlugin.java
===================================================================
--- applications/editors/josm/plugins/waydownloader/src/org/openstreetmap/josm/plugins/waydownloader/WayDownloaderPlugin.java	(revision 18601)
+++ applications/editors/josm/plugins/waydownloader/src/org/openstreetmap/josm/plugins/waydownloader/WayDownloaderPlugin.java	(revision 18613)
@@ -7,5 +7,7 @@
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.LinkedList;
+import java.util.List;
 import java.util.concurrent.Future;
 
@@ -16,9 +18,13 @@
 import org.openstreetmap.josm.actions.MergeNodesAction;
 import org.openstreetmap.josm.actions.downloadtasks.DownloadOsmTask;
+import org.openstreetmap.josm.command.Command;
 import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.data.osm.BBox;
+import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.data.osm.DataSource;
 import org.openstreetmap.josm.data.osm.Node;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.gui.DefaultNameFormatter;
 import org.openstreetmap.josm.gui.MainMenu;
 import org.openstreetmap.josm.gui.progress.PleaseWaitProgressMonitor;
@@ -47,93 +53,107 @@
         /** Set up the action (text appearing on the menu, keyboard shortcut etc */
         public WayDownloadAction() {
-
-            super( "Way Download" ,
+            super( tr("Way Download") ,
                     "way-download",
-                    "Download map data on the end of selected way",
+                    tr("Download map data on the end of selected way"),
                     Shortcut.registerShortcut("waydownloader:waydownload", "Way Download", KeyEvent.VK_W, Shortcut.GROUP_MENU, Shortcut.SHIFT_DEFAULT),
                     true);
         }
 
+        protected void showWarningMessage(String msg) {
+        	 if(msg == null) return;
+             JOptionPane.showMessageDialog(
+             		Main.parent, 
+             		msg,
+             		tr("Warning"),
+             		JOptionPane.WARNING_MESSAGE                		
+             );
+        }
+        
+        protected void showErrorMessage(String msg) {
+       	 if(msg == null) return;
+	        JOptionPane.showMessageDialog(
+	        		Main.parent, 
+	        		msg,
+	        		tr("Error"),
+	        		JOptionPane.ERROR_MESSAGE                		
+	        );
+       }
+        
+        protected void showInfoMessage(String msg) {
+          	 if(msg == null) return;
+               JOptionPane.showMessageDialog(
+               		Main.parent, 
+               		msg,
+               		tr("Information"),
+               		JOptionPane.INFORMATION_MESSAGE                		
+               );
+          }
+        
         /** Called when the WayDownloadAction action is triggered (e.g. user clicked the menu option) */
         public void actionPerformed(ActionEvent e) {
-
-            System.out.println("Way Download");
-
-            String errMsg = null;
-
             selectedNode = null;
             Collection<OsmPrimitive> selection = Main.main.getCurrentDataSet().getSelectedNodes();
-
             if (selection.size()==0) {
                 selection = Main.main.getCurrentDataSet().getSelectedWays();
                 if (!workFromWaySelection(selection)) {
-                    errMsg = tr("Select a starting node on the end of a way");
+                	showWarningMessage(tr("<html>Neither a node nor a way with an endpoint outside of the<br>current download areas is selected.<br>Select a node on the start or end of a way or an entire way first.</html>"));
+                	return;
                 }
                 selection = Main.main.getCurrentDataSet().getSelectedNodes();
             }
 
-            if ( selection.size()==0 || selection.size()>1 ) {
-                errMsg = tr("Select a starting node on the end of a way");
-            } else {
-                OsmPrimitive p = selection.iterator().next();
-
-
-
-                if (!(p instanceof Node)) {
-                    errMsg = tr("Select a starting node on the end of a way");
-                } else {
-                    selectedNode = (Node) p;
-
-
-                    Main.map.mapView.zoomTo(selectedNode.getEastNorth());
-
-                    //Before downloading. Figure a few things out.
-                    //Find connected way
-                    ArrayList<Way> connectedWays = findConnectedWays();
-
-                    if (connectedWays.size()==0) {
-                        errMsg = tr("Select a starting node on the end of a way");
-                    } else {
-                        priorConnectedWay =connectedWays.get(0);
-
-                        //Download a little rectangle around the selected node
-                        double latbuffer=0.0003; //TODO make this an option
-                        double lonbuffer=0.0005;
-                        DownloadOsmTask downloadTask = new DownloadOsmTask();
-                        final PleaseWaitProgressMonitor monitor = new PleaseWaitProgressMonitor();
-                        final Future<?> future = downloadTask.download(
-                        		false /* no new layer */,
-                        		new Bounds(
-                        				selectedNode.getCoor().lat()- latbuffer,
-                        				selectedNode.getCoor().lon()- lonbuffer,
-                        				selectedNode.getCoor().lat()+ latbuffer,
-                        				selectedNode.getCoor().lon()+ lonbuffer
-                        		),
-                        		monitor
-                        );
-                        // schedule closing of the progress monitor after the download
-                        // job has finished
-                        Main.worker.submit(
-                                new Runnable() {
-                                    public void run() {
-                                        try {
-                                            future.get();
-                                        } catch(Exception e) {
-                                            e.printStackTrace();
-                                            return;
-                                        }
-                                        monitor.close();
-                                    }
-                                }
-                        );
-                        //The download is scheduled to be executed.
-                        //Now schedule the run() method (below) to be executed once that's completed.
-                        Main.worker.execute(this);
+            if ( selection.size()==0 || selection.size()>1 || ! (selection.iterator().next() instanceof Node)) {
+            	showWarningMessage(tr("<html>Could not find a unique node to start downloading from.</html>"));
+                return;
+            } 
+        
+            selectedNode = (Node) selection.iterator().next();
+            Main.map.mapView.zoomTo(selectedNode.getEastNorth());
+
+            //Before downloading. Figure a few things out.
+            //Find connected way
+            List<Way> connectedWays = findConnectedWays(selectedNode);
+            if (connectedWays.size()==0) {
+            	showWarningMessage(
+            			tr("<html>There are no ways connected to node ''{0}''. Aborting.</html>",
+            			selectedNode.getDisplayName(DefaultNameFormatter.getInstance()))
+            	);
+            	return;
+            } 
+            priorConnectedWay =connectedWays.get(0);
+
+            //Download a little rectangle around the selected node
+            double latbuffer=0.0003; //TODO make this an option
+            double lonbuffer=0.0005;
+            DownloadOsmTask downloadTask = new DownloadOsmTask();
+            final PleaseWaitProgressMonitor monitor = new PleaseWaitProgressMonitor();
+            final Future<?> future = downloadTask.download(
+            		false /* no new layer */,
+            		new Bounds(
+            				selectedNode.getCoor().lat()- latbuffer,
+            				selectedNode.getCoor().lon()- lonbuffer,
+            				selectedNode.getCoor().lat()+ latbuffer,
+            				selectedNode.getCoor().lon()+ lonbuffer
+            		),
+            		monitor
+            );
+            // schedule closing of the progress monitor after the download
+            // job has finished
+            Main.worker.submit(
+                    new Runnable() {
+                        public void run() {
+                            try {
+                                future.get();
+                            } catch(Exception e) {
+                                e.printStackTrace();
+                                return;
+                            }
+                            monitor.close();
+                        }
                     }
-                }
-            }
-
-            if(errMsg != null)
-                JOptionPane.showMessageDialog(Main.parent, errMsg);
+            );
+            //The download is scheduled to be executed.
+            //Now schedule the run() method (below) to be executed once that's completed.
+            Main.worker.execute(this);
         }
 
@@ -143,42 +163,70 @@
         public void run() {
             //Find ways connected to the node after the download
-            ArrayList<Way> connectedWays = findConnectedWays();
-
-            String errMsg = null;
+            List<Way> connectedWays = findConnectedWays(selectedNode);
+
             if (connectedWays.size()==0) {
-                throw new RuntimeException("Way downloader data inconsistency. priorConnectedWay (" +
-                        priorConnectedWay.toString() + ") wasn't discovered after download");
-
-            } else if (connectedWays.size()==1) {
-                //Just one way connecting the node still. Presumably the one which was there before
-
+            	String msg = tr("Way downloader data inconsistency. Prior connected way ''{0}'' wasn''t discovered after download",
+                				priorConnectedWay.getDisplayName(DefaultNameFormatter.getInstance())
+                		);
+            	System.err.println(msg);
+            	showErrorMessage(msg);
+            	return;                
+            } 
+            
+            if (connectedWays.size()==1) {
+                //Just one way connecting still to the node . Presumably the one which was there before
                 //Check if it's just a duplicate node
-                Node dupeNode = duplicateNode();
+            	
+                Node dupeNode = findDuplicateNode(selectedNode);
                 if (dupeNode!=null) {
-
-                    if (JOptionPane.showConfirmDialog(null, "Merge duplicate node?")==JOptionPane.YES_OPTION) {
-                        LinkedList<Node> dupeNodes = new LinkedList<Node>();
-                        dupeNodes.add(dupeNode);
-                        MergeNodesAction.mergeNodes(Main.main.getEditLayer(),
-                        dupeNodes, selectedNode);
-
-                        connectedWays = findConnectedWays(); //Carry on
+                	String msg = tr("<html>There aren''t further connected ways to download.<br>"
+                			+ "A potential duplicate node of the currently selected node was found, though.<br><br>"
+                			+ "The currently selected node is ''{0}''<br>"
+                			+ "The potential duplicate node is ''{1}''<br>"
+                			+ "Merge the duplicate node onto the currently selected node and continue way downloading?"
+                			+ "</html>",
+                			selectedNode.getDisplayName(DefaultNameFormatter.getInstance()),
+                			dupeNode.getDisplayName(DefaultNameFormatter.getInstance())
+                	);
+                			
+                	int ret = JOptionPane.showConfirmDialog(
+                			Main.parent,
+                			msg,
+                			tr("Merge duplicate node?"),
+                			JOptionPane.YES_NO_OPTION,
+                			JOptionPane.QUESTION_MESSAGE
+                	);
+                	if (ret != JOptionPane.YES_OPTION)
+                		return;
+                    Command cmd = MergeNodesAction.mergeNodes(
+                    		Main.main.getEditLayer(),
+                    		Collections.singletonList(dupeNode), 
+                    		selectedNode
+                    );
+                    if (cmd != null) {
+                        Main.main.undoRedo.add(cmd);
+                        Main.main.getEditLayer().data.setSelected(selectedNode);
                     }
-
-
+                    connectedWays = findConnectedWays(selectedNode);
                 } else {
-                    errMsg = tr("Reached the end of the line");
-                }
-
-            }
-
+                	showInfoMessage(tr("<html>No more connected ways to download.</html>"));
+                	return;
+                }                
+                return;
+            } 
+            
             if (connectedWays.size()>2) {
                 //Three or more ways meeting at this node. Means we have a junction.
-                errMsg = tr("Reached a junction");
-
-            } else if (connectedWays.size()==2) {
+            	String msg = tr(
+            			"Node ''{0}'' is a junction with more than 2 connected ways.",
+            			selectedNode.getDisplayName(DefaultNameFormatter.getInstance())
+            	);
+            	showWarningMessage(msg);
+            	return;
+            } 
+            
+            if (connectedWays.size()==2) {
                 //Two connected ways (The "normal" way downloading case)
                 //Figure out which of the two is new.
-                System.out.println("connectedWays.toString()=" + connectedWays.toString());
                 Way wayA = connectedWays.get(0);
                 Way wayB = connectedWays.get(1);
@@ -190,21 +238,34 @@
                 //Select the next node
                 Main.main.getCurrentDataSet().setSelected(nextNode);
-
                 Main.map.mapView.zoomTo(nextNode.getEastNorth());
             }
-            if(errMsg != null)
-                JOptionPane.showMessageDialog(Main.parent, errMsg);
-        }
-    }
-
-    /** See if there's another node at the same coordinates. If so return it. Otherwise null */
-    private Node duplicateNode() {
-        for (Node onNode:Main.main.getCurrentDataSet().getNodes()) {
-            if (!onNode.equals(this.selectedNode)
-                    && !onNode.incomplete
-                    && onNode.getCoor().lat()==selectedNode.getCoor().lat()
-                    && onNode.getCoor().lon()==selectedNode.getCoor().lon()) {
-                return onNode;
-            }
+        }
+
+		@Override
+		protected void updateEnabledState() { 
+			setEnabled(getEditLayer() != null);
+		}
+
+		@Override
+		protected void updateEnabledState(
+				Collection<? extends OsmPrimitive> selection) {
+			// do nothing
+		}
+    }
+
+    /** 
+     * Check whether there is a potentially duplicate node for <code>referenceNode</code>.
+     * 
+     * @param referenceNode the reference node 
+     * @return the potential duplicate node. null, if no duplicate found.
+     */
+    private Node findDuplicateNode(Node referenceNode) {
+    	DataSet ds = Main.main.getCurrentDataSet();
+    	List<Node> candidates = ds.searchNodes(new BBox(new Bounds(referenceNode.getCoor(), 0.0003, 0.0005)));
+        for (Node candidate: candidates) {
+            if (!candidate.equals(referenceNode)
+                    && !candidate.incomplete
+                    && candidate.getCoor().equals(referenceNode.getCoor()))
+                return candidate;            
         }
         return null;
@@ -218,15 +279,19 @@
     }
 
-    /** find set of ways which have an end on the selectedNode */
-    private ArrayList<Way> findConnectedWays() {
-        ArrayList<Way> connectedWays = new ArrayList<Way>();
-
-        //loop through every way
-        for (Way onWay:Main.main.getCurrentDataSet().getWays()) {
-            if (onWay.getNodesCount() >= 2) {
-                if (onWay.isFirstLastNode(selectedNode)) {
-                    //Found it
-                    connectedWays.add(onWay);
-                }
+    /** 
+     * Replies the list of ways <code>referenceNode</code> is either the first or the 
+     * last node in.
+     * 
+     * @param referenceNode the reference node 
+     * @return the list of ways. May be empty, but null.
+     */
+    private List<Way> findConnectedWays(Node referenceNode) {
+    	List<Way> referers = OsmPrimitive.getFilteredList(referenceNode.getReferrers(), Way.class);
+        ArrayList<Way> connectedWays = new ArrayList<Way>(referers.size());
+
+        //loop through referers
+        for (Way way: referers) {
+            if (way.getNodesCount() >= 2 && way.isFirstLastNode(referenceNode)) {
+                    connectedWays.add(way);
             }
         }
@@ -239,5 +304,4 @@
      */
     private boolean workFromWaySelection(Collection<OsmPrimitive> selection) {
-
         if (selection.size() != 1)
             return false;
@@ -257,11 +321,5 @@
         for (DataSource datasource:Main.main.getCurrentDataSet().dataSources) {
             Bounds bounds = datasource.bounds;
-
-            if (node.getCoor().lat()>bounds.getMin().lat() &&
-                node.getCoor().lat()<bounds.getMax().lat() &&
-                node.getCoor().lon()>bounds.getMin().lon() &&
-                node.getCoor().lon()<bounds.getMax().lon()) {
-                return true;
-            }
+            if (bounds != null && bounds.contains(node.getCoor())) return true;
         }
         return false;
