Index: /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/OSMValidatorPlugin.java
===================================================================
--- /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/OSMValidatorPlugin.java	(revision 9683)
+++ /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/OSMValidatorPlugin.java	(revision 9684)
@@ -23,19 +23,19 @@
 
 /**
- * 
+ *
  * A OSM data validator
- * 
+ *
  * @author Francisco R. Santos <frsantos@gmail.com>
  */
 public class OSMValidatorPlugin extends Plugin implements LayerChangeListener
 {
-    /** The validate action */
-    ValidateAction validateAction = new ValidateAction(this);
-    
-    /** The validation dialog */
-    ValidatorDialog validationDialog;
-    
-    /** The list of errors per layer*/
-    Map<Layer, List<TestError>> layerErrors = new HashMap<Layer, List<TestError>>();
+	/** The validate action */
+	ValidateAction validateAction = new ValidateAction(this);
+
+	/** The validation dialog */
+	ValidatorDialog validationDialog;
+
+	/** The list of errors per layer*/
+	Map<Layer, List<TestError>> layerErrors = new HashMap<Layer, List<TestError>>();
 
 	/**
@@ -45,17 +45,17 @@
 	public static Class[] allAvailableTests = new Class[]
 	{
-		DuplicateNode.class,
-		OverlappingWays.class,
-		UntaggedNode.class,
-		UntaggedWay.class,
-		SelfIntersectingWay.class,
-		DuplicatedWayNodes.class,
-		CrossingWays.class,
-		SimilarNamedWays.class,
-		NodesWithSameName.class,
-		Coastlines.class,
-		WronglyOrderedWays.class,
-		UnclosedWays.class,
-		TagChecker.class,
+		DuplicateNode.class,       // ID    1 ..   99
+		OverlappingWays.class,     // ID  101 ..  199
+		UntaggedNode.class,        // ID  201 ..  299
+		UntaggedWay.class,         // ID  301 ..  399
+		SelfIntersectingWay.class, // ID  401 ..  499
+		DuplicatedWayNodes.class,  // ID  501 ..  599
+		CrossingWays.class,        // ID  601 ..  699
+		SimilarNamedWays.class,    // ID  701 ..  799
+		NodesWithSameName.class,   // ID  801 ..  899
+		Coastlines.class,          // ID  901 ..  999
+		WronglyOrderedWays.class,  // ID 1001 .. 1099
+		UnclosedWays.class,        // ID 1101 .. 1199
+		TagChecker.class,          // ID 1201 .. 1299
 	};
 
@@ -70,5 +70,5 @@
 
 	@Override
-	public PreferenceSetting getPreferenceSetting() 
+	public PreferenceSetting getPreferenceSetting()
 	{
 		return new PreferenceEditor(this);
@@ -76,20 +76,20 @@
 
 	@Override
-	public void mapFrameInitialized(MapFrame oldFrame, MapFrame newFrame) 
+	public void mapFrameInitialized(MapFrame oldFrame, MapFrame newFrame)
 	{
 		if (newFrame != null)
 		{
-		    validationDialog = new ValidatorDialog(this);
-	        newFrame.addToggleDialog(validationDialog);
-            Main.main.addLayer(new ErrorLayer(this));
-        	if( Main.pref.hasKey(PreferenceEditor.PREF_DEBUG + ".grid") )
-        		Main.main.addLayer(new GridLayer(tr("Grid")));
-            Layer.listeners.add(this); 
+			validationDialog = new ValidatorDialog(this);
+			newFrame.addToggleDialog(validationDialog);
+			Main.main.addLayer(new ErrorLayer(this));
+			if( Main.pref.hasKey(PreferenceEditor.PREF_DEBUG + ".grid") )
+				Main.main.addLayer(new GridLayer(tr("Grid")));
+			Layer.listeners.add(this);
 		}
 		else
-            Layer.listeners.remove(this); 
-        
+			Layer.listeners.remove(this);
+
 		LinkedList<UploadHook> hooks = ((UploadAction)Main.main.menu.upload).uploadHooks;
-		Iterator<UploadHook> hooksIt = hooks.iterator(); 
+		Iterator<UploadHook> hooksIt = hooks.iterator();
 		while( hooksIt.hasNext() )
 		{
@@ -161,14 +161,14 @@
 	}
 
-    /**
-     * Gets the list of all available test classes
-     * 
-     * @return An array of the test classes	        validationDialog.tree.setErrorList(errors);
-     */
-    public static Class[] getAllAvailableTests()
-    {
-        return allAvailableTests;
-    }
-    
+	/**
+	 * Gets the list of all available test classes
+	 *
+	 * @return An array of the test classes
+	 */
+	public static Class[] getAllAvailableTests()
+	{
+		return allAvailableTests;
+	}
+
 	/**
 	 * Initializes all tests
@@ -185,29 +185,31 @@
 					test.getClass().getMethod("initialize", new Class[] { OSMValidatorPlugin.class} ).invoke(null, new Object[] {this});
 				}
-			} 
-            catch(InvocationTargetException ite) 
-            {
-                ite.getCause().printStackTrace();
-                JOptionPane.showMessageDialog(null, tr("Error initializing test {0}:\n {1}", test.getClass().getSimpleName(), ite.getCause().getMessage()));
-            }
-            catch(Exception e) 
-            {
-                e.printStackTrace();
-                JOptionPane.showMessageDialog(null, tr("Error initializing test {0}:\n {1}", test.getClass().getSimpleName(), e));
-            }
-		}
-	}
-	
-	public void activeLayerChange(Layer oldLayer, Layer newLayer) 
+			}
+			catch(InvocationTargetException ite)
+			{
+				ite.getCause().printStackTrace();
+				JOptionPane.showMessageDialog(null, tr("Error initializing test {0}:\n {1}",
+				test.getClass().getSimpleName(), ite.getCause().getMessage()));
+			}
+			catch(Exception e)
+			{
+				e.printStackTrace();
+				JOptionPane.showMessageDialog(null, tr("Error initializing test {0}:\n {1}",
+				test.getClass().getSimpleName(), e));
+			}
+		}
+	}
+
+	public void activeLayerChange(Layer oldLayer, Layer newLayer)
 	{
 		if( newLayer instanceof OsmDataLayer )
 		{
-	        List<TestError> errors = layerErrors.get(newLayer);
-	        validationDialog.tree.setErrorList(errors);
-			Main.map.repaint();	        
-		}
-	}
-
-	public void layerAdded(Layer newLayer) 
+			List<TestError> errors = layerErrors.get(newLayer);
+			validationDialog.tree.setErrorList(errors);
+			Main.map.repaint();
+		}
+	}
+
+	public void layerAdded(Layer newLayer)
 	{
 		if( newLayer instanceof OsmDataLayer )
@@ -217,5 +219,5 @@
 	}
 
-	public void layerRemoved(Layer oldLayer) 
+	public void layerRemoved(Layer oldLayer)
 	{
 		layerErrors.remove(oldLayer);
Index: /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/TestError.java
===================================================================
--- /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/TestError.java	(revision 9683)
+++ /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/TestError.java	(revision 9684)
@@ -33,8 +33,8 @@
 	private Test tester;
 	/** Internal code used by testers to classify errors */
-	private int internalCode = -1;
+	private int code;
 	/** If this error is selected */
 	private boolean selected;
-	
+
 	/**
 	 * Constructors
@@ -44,7 +44,7 @@
 	 * @param primitive The affected primitive
 	 * @param primitives The affected primitives
-	 * @param internalCode The internal code
-	 */
-	public TestError(Test tester, Severity severity, String message, String description,
+	 * @param code The test error reference code
+	 */
+	public TestError(Test tester, Severity severity, String message, String description, int code,
 			List<? extends OsmPrimitive> primitives, List<?> highlighted) {
 		this.tester = tester;
@@ -54,34 +54,25 @@
 		this.primitives = primitives;
 		this.highlighted = highlighted;
-	}
-	public TestError(Test tester, Severity severity, String message, List<? extends OsmPrimitive> primitives, List<?> highlighted)
-	{
-		this(tester, severity, message, null, primitives, highlighted);
-	}
-	public TestError(Test tester, Severity severity, String message, String description, List<? extends OsmPrimitive> primitives)
-	{
-		this(tester, severity, message, description, primitives, primitives);
-	}
-	public TestError(Test tester, Severity severity, String message, List<? extends OsmPrimitive> primitives)
-	{
-		this(tester, severity, message, null, primitives, primitives);
-	}
-	public TestError(Test tester, Severity severity, String message, OsmPrimitive primitive)
-	{
-		this(tester, severity, message, null, Collections.singletonList(primitive), Collections.singletonList(primitive));
-	}
-	public TestError(Test tester, Severity severity, String message, String description, OsmPrimitive primitive)
-	{
-		this(tester, severity, message, description, Collections.singletonList(primitive));
-	}
-	public TestError(Test tester, Severity severity, String message, OsmPrimitive primitive, int internalCode)
-	{
-		this(tester, severity, message, null, primitive);
-		this.internalCode = internalCode;
-	}
-	public TestError(Test tester, Severity severity, String message, String description, OsmPrimitive primitive, int internalCode)
-	{
-		this(tester, severity, message, description, primitive);
-		this.internalCode = internalCode;
+		this.code = code;
+	}
+	public TestError(Test tester, Severity severity, String message, int code, List<? extends OsmPrimitive> primitives, List<?> highlighted)
+	{
+		this(tester, severity, message, null, code, primitives, highlighted);
+	}
+	public TestError(Test tester, Severity severity, String message, String description, int code, List<? extends OsmPrimitive> primitives)
+	{
+		this(tester, severity, message, description, code, primitives, primitives);
+	}
+	public TestError(Test tester, Severity severity, String message, int code, List<? extends OsmPrimitive> primitives)
+	{
+		this(tester, severity, message, null, code, primitives, primitives);
+	}
+	public TestError(Test tester, Severity severity, String message, int code, OsmPrimitive primitive)
+	{
+		this(tester, severity, message, null, code, Collections.singletonList(primitive), Collections.singletonList(primitive));
+	}
+	public TestError(Test tester, Severity severity, String message, String description, int code, OsmPrimitive primitive)
+	{
+		this(tester, severity, message, description, code, Collections.singletonList(primitive));
 	}
 
@@ -108,14 +99,14 @@
 	 * @param message The error message
 	 */
-	public void setMessage(String message) 
+	public void setMessage(String message)
 	{
 		this.message = message;
 	}
-	
-	/**
-	 * Gets the list of primitives affected by this error 
+
+	/**
+	 * Gets the list of primitives affected by this error
 	 * @return the list of primitives affected by this error
 	 */
-	public List<? extends OsmPrimitive> getPrimitives() 
+	public List<? extends OsmPrimitive> getPrimitives()
 	{
 		return primitives;
@@ -123,9 +114,9 @@
 
 	/**
-	 * Sets the list of primitives affected by this error 
+	 * Sets the list of primitives affected by this error
 	 * @param primitives the list of primitives affected by this error
 	 */
 
-	public void setPrimitives(List<OsmPrimitive> primitives) 
+	public void setPrimitives(List<OsmPrimitive> primitives)
 	{
 		this.primitives = primitives;
@@ -136,5 +127,5 @@
 	 * @return the severity of this error
 	 */
-	public Severity getSeverity() 
+	public Severity getSeverity()
 	{
 		return severity;
@@ -145,5 +136,5 @@
 	 * @param severity the severity of this error
 	 */
-	public void setSeverity(Severity severity) 
+	public void setSeverity(Severity severity)
 	{
 		this.severity = severity;
@@ -156,5 +147,5 @@
 	{
 		Collection<String> strings = new TreeSet<String>();
-		String ignorestring = message;
+		String ignorestring = Integer.toString(code);
 		for (OsmPrimitive o : primitives)
 		{
@@ -195,21 +186,12 @@
 
 	/**
-	 * Gets the internal code
-	 * @return the internal code
-	 */
-	public int getInternalCode()
-	{
-		return internalCode;
-	}
-
-	/**
-	 * Sets the internal code
-	 * @param internalCode The internal code
-	 */
-	public void setInternalCode(int internalCode) 
-	{
-		this.internalCode = internalCode;
-	}
-	
+	 * Gets the code
+	 * @return the code
+	 */
+	public int getCode()
+	{
+		return code;
+	}
+
 	/**
 	 * Returns true if the error can be fixed automatically
@@ -255,97 +237,97 @@
 	}
 
-    /**
-     * Visitor that highlights the primitives affected by this error
-     * @author frsantos
-     */
-    class PaintVisitor implements Visitor
-    {
-        /** The graphics */
-        private final Graphics g;
-        /** The MapView */
-        private final MapView mv;
-        
-        /**
-         * Constructor 
-         * @param g The graphics 
-         * @param mv The Mapview
-         */
-        public PaintVisitor(Graphics g, MapView mv)
-        {
-            this.g = g;
-            this.mv = mv;
-        }
+	/**
+	 * Visitor that highlights the primitives affected by this error
+	 * @author frsantos
+	 */
+	class PaintVisitor implements Visitor
+	{
+		/** The graphics */
+		private final Graphics g;
+		/** The MapView */
+		private final MapView mv;
+
+		/**
+		 * Constructor
+		 * @param g The graphics
+		 * @param mv The Mapview
+		 */
+		public PaintVisitor(Graphics g, MapView mv)
+		{
+			this.g = g;
+			this.mv = mv;
+		}
 
 		public void visit(OsmPrimitive p) {
-            if (!p.deleted && !p.incomplete) {
-                p.visit(this);
-			}
-		}
-
-        /**
-         * Draws a circle around the node 
-         * @param n The node
-         * @param color The circle color
-         */
-        public void drawNode(Node n, Color color)
-        {
-            Point p = mv.getPoint(n.eastNorth);
-            g.setColor(color);
-            if( selected )
-            {
-                g.fillOval(p.x-5, p.y-5, 10, 10);
-            }
-            else
-                g.drawOval(p.x-5, p.y-5, 10, 10);
-        }
-
-        /**
-         * Draws a line around the segment
-         * 
-         * @param s The segment
-         * @param color The color
-         */
-        public void drawSegment(Node n1, Node n2, Color color)
-        {
-            Point p1 = mv.getPoint(n1.eastNorth);
-            Point p2 = mv.getPoint(n2.eastNorth);
-            g.setColor(color);
-            
-            double t = Math.atan2(p2.x-p1.x, p2.y-p1.y);
-            double cosT = Math.cos(t);
-            double sinT = Math.sin(t);
-            int deg = (int)Math.toDegrees(t);
-            if( selected )
-            {
-                int[] x = new int[] {(int)(p1.x + 5*cosT), (int)(p2.x + 5*cosT), (int)(p2.x - 5*cosT), (int)(p1.x - 5*cosT)};
-                int[] y = new int[] {(int)(p1.y - 5*sinT), (int)(p2.y - 5*sinT), (int)(p2.y + 5*sinT), (int)(p1.y + 5*sinT)};
-                g.fillPolygon(x, y, 4);
-                g.fillArc(p1.x-5, p1.y-5, 10, 10, deg, 180 );
-                g.fillArc(p2.x-5, p2.y-5, 10, 10, deg, -180);
-            }
-            else
-            {
-                g.drawLine((int)(p1.x + 5*cosT), (int)(p1.y - 5*sinT), (int)(p2.x + 5*cosT), (int)(p2.y - 5*sinT));
-                g.drawLine((int)(p1.x - 5*cosT), (int)(p1.y + 5*sinT), (int)(p2.x - 5*cosT), (int)(p2.y + 5*sinT));
-                g.drawArc(p1.x-5, p1.y-5, 10, 10, deg, 180 );
-                g.drawArc(p2.x-5, p2.y-5, 10, 10, deg, -180);
-            }
-        }
-
-        
-        /**
-         * Draw a small rectangle. 
-         * White if selected (as always) or red otherwise.
-         * 
-         * @param n The node to draw.
-         */
-        public void visit(Node n) 
-        {
-            if( isNodeVisible(n) )
-                drawNode(n, severity.getColor());
-        }
-
-        public void visit(Way w)
-        {
+			if (!p.deleted && !p.incomplete) {
+				p.visit(this);
+			}
+		}
+
+		/**
+		 * Draws a circle around the node
+		 * @param n The node
+		 * @param color The circle color
+		 */
+		public void drawNode(Node n, Color color)
+		{
+			Point p = mv.getPoint(n.eastNorth);
+			g.setColor(color);
+			if( selected )
+			{
+				g.fillOval(p.x-5, p.y-5, 10, 10);
+			}
+			else
+				g.drawOval(p.x-5, p.y-5, 10, 10);
+		}
+
+		/**
+		 * Draws a line around the segment
+		 *
+		 * @param s The segment
+		 * @param color The color
+		 */
+		public void drawSegment(Node n1, Node n2, Color color)
+		{
+			Point p1 = mv.getPoint(n1.eastNorth);
+			Point p2 = mv.getPoint(n2.eastNorth);
+			g.setColor(color);
+
+			double t = Math.atan2(p2.x-p1.x, p2.y-p1.y);
+			double cosT = Math.cos(t);
+			double sinT = Math.sin(t);
+			int deg = (int)Math.toDegrees(t);
+			if( selected )
+			{
+				int[] x = new int[] {(int)(p1.x + 5*cosT), (int)(p2.x + 5*cosT), (int)(p2.x - 5*cosT), (int)(p1.x - 5*cosT)};
+				int[] y = new int[] {(int)(p1.y - 5*sinT), (int)(p2.y - 5*sinT), (int)(p2.y + 5*sinT), (int)(p1.y + 5*sinT)};
+				g.fillPolygon(x, y, 4);
+				g.fillArc(p1.x-5, p1.y-5, 10, 10, deg, 180 );
+				g.fillArc(p2.x-5, p2.y-5, 10, 10, deg, -180);
+			}
+			else
+			{
+				g.drawLine((int)(p1.x + 5*cosT), (int)(p1.y - 5*sinT), (int)(p2.x + 5*cosT), (int)(p2.y - 5*sinT));
+				g.drawLine((int)(p1.x - 5*cosT), (int)(p1.y + 5*sinT), (int)(p2.x - 5*cosT), (int)(p2.y + 5*sinT));
+				g.drawArc(p1.x-5, p1.y-5, 10, 10, deg, 180 );
+				g.drawArc(p2.x-5, p2.y-5, 10, 10, deg, -180);
+			}
+		}
+
+
+		/**
+		 * Draw a small rectangle.
+		 * White if selected (as always) or red otherwise.
+		 *
+		 * @param n The node to draw.
+		 */
+		public void visit(Node n)
+		{
+			if( isNodeVisible(n) )
+				drawNode(n, severity.getColor());
+		}
+
+		public void visit(Way w)
+		{
 			Node lastN = null;
 			for (Node n : w.nodes) {
@@ -354,11 +336,11 @@
 					continue;
 				}
-                if (isSegmentVisible(lastN, n))
-                {
-                    drawSegment(lastN, n, severity.getColor());
-                }
+				if (isSegmentVisible(lastN, n))
+				{
+					drawSegment(lastN, n, severity.getColor());
+				}
 				lastN = n;
 			}
-        }
+		}
 
 		public void visit(WaySegment ws) {
@@ -375,40 +357,40 @@
 			/* No idea how to draw a relation. */
 		}
-        
-        /**
-         * Checks if the given node is in the visible area.
-         * @param n The node to check for visibility
-         * @return true if the node is visible
-         */
-        protected boolean isNodeVisible(Node n) {
-            Point p = mv.getPoint(n.eastNorth);
-            return !((p.x < 0) || (p.y < 0) || (p.x > mv.getWidth()) || (p.y > mv.getHeight()));
-        }
-
-        /**
-         * Checks if the given segment is in the visible area.
-         * NOTE: This will return true for a small number of non-visible
-         *       segments.
-         * @param ls The segment to check
-         * @return true if the segment is visible
-         */
-        protected boolean isSegmentVisible(Node n1, Node n2) {
-            Point p1 = mv.getPoint(n1.eastNorth);
-            Point p2 = mv.getPoint(n2.eastNorth);
-            if ((p1.x < 0) && (p2.x < 0)) return false;
-            if ((p1.y < 0) && (p2.y < 0)) return false;
-            if ((p1.x > mv.getWidth()) && (p2.x > mv.getWidth())) return false;
-            if ((p1.y > mv.getHeight()) && (p2.y > mv.getHeight())) return false;
-            return true;
-        }
-    }
-
-    /**
-     * Sets the selection flag of this error
-     * @param selected if this error is selected
-     */
-    public void setSelected(boolean selected)
-    {
-        this.selected = selected;
-    }
+
+		/**
+		 * Checks if the given node is in the visible area.
+		 * @param n The node to check for visibility
+		 * @return true if the node is visible
+		 */
+		protected boolean isNodeVisible(Node n) {
+			Point p = mv.getPoint(n.eastNorth);
+			return !((p.x < 0) || (p.y < 0) || (p.x > mv.getWidth()) || (p.y > mv.getHeight()));
+		}
+
+		/**
+		 * Checks if the given segment is in the visible area.
+		 * NOTE: This will return true for a small number of non-visible
+		 *		 segments.
+		 * @param ls The segment to check
+		 * @return true if the segment is visible
+		 */
+		protected boolean isSegmentVisible(Node n1, Node n2) {
+			Point p1 = mv.getPoint(n1.eastNorth);
+			Point p2 = mv.getPoint(n2.eastNorth);
+			if ((p1.x < 0) && (p2.x < 0)) return false;
+			if ((p1.y < 0) && (p2.y < 0)) return false;
+			if ((p1.x > mv.getWidth()) && (p2.x > mv.getWidth())) return false;
+			if ((p1.y > mv.getHeight()) && (p2.y > mv.getHeight())) return false;
+			return true;
+		}
+	}
+
+	/**
+	 * Sets the selection flag of this error
+	 * @param selected if this error is selected
+	 */
+	public void setSelected(boolean selected)
+	{
+		this.selected = selected;
+	}
 }
Index: /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/Coastlines.java
===================================================================
--- /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/Coastlines.java	(revision 9683)
+++ /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/Coastlines.java	(revision 9684)
@@ -16,18 +16,20 @@
 /**
  * Check coastlines for errors
- * 
+ *
  * @author frsantos
  */
-public class Coastlines extends Test 
+public class Coastlines extends Test
 {
-    /** All ways, grouped by cells */
-    Map<Point2D,List<Way>> _cellWays;
-    /** The already detected errors */
-    Bag<Way, Way> _errorWays;
+	protected static int UNORDERED_COASTLINES = 901;
+
+	/** All ways, grouped by cells */
+	Map<Point2D,List<Way>> _cellWays;
+	/** The already detected errors */
+	Bag<Way, Way> _errorWays;
 
 	/**
 	 * Constructor
 	 */
-	public Coastlines() 
+	public Coastlines()
 	{
 		super(tr("Coastlines."),
@@ -35,51 +37,51 @@
 	}
 
-    @Override
-    public void startTest() 
-    {
-        _cellWays = new HashMap<Point2D,List<Way>>(1000);
-        _errorWays = new Bag<Way, Way>();
-    }
+	@Override
+	public void startTest()
+	{
+		_cellWays = new HashMap<Point2D,List<Way>>(1000);
+		_errorWays = new Bag<Way, Way>();
+	}
 
-    @Override
-    public void endTest() 
-    {
-        _cellWays = null;
-        _errorWays = null;
-    }
-    
 	@Override
-	public void visit(Way w) 
+	public void endTest()
 	{
-        if( w.deleted || w.incomplete )
-            return;
-        
-        String natural = w.get("natural");
-        if( natural == null || !natural.equals("coastline") )
-            return;
-        
-        List<List<Way>> cellWays = Util.getWaysInCell(w, _cellWays);
-        for( List<Way> ways : cellWays)
-        {
-            for( Way w2 : ways)
-            {
-                if( _errorWays.contains(w, w2) || _errorWays.contains(w2, w) )
-                	continue;
-                
-                String natural2 = w.get("natural");
-                if( natural2 == null || !natural2.equals("coastline") )
-                    continue;
-                
-                if( w.nodes.get(0).equals(w2.nodes.get(0)) || w.nodes.get(w.nodes.size() - 1).equals(w2.nodes.get(w2.nodes.size() - 1)))
-                {
-                    List<OsmPrimitive> primitives = new ArrayList<OsmPrimitive>();
-                    primitives.add(w);
-                    primitives.add(w2);
-                    errors.add( new TestError(this, Severity.ERROR, tr("Unordered coastline"), primitives) );
-                    _errorWays.add(w, w2);
-                }
-            }
-            ways.add(w);
-        }
+		_cellWays = null;
+		_errorWays = null;
+	}
+
+	@Override
+	public void visit(Way w)
+	{
+		if( w.deleted || w.incomplete )
+			return;
+
+		String natural = w.get("natural");
+		if( natural == null || !natural.equals("coastline") )
+			return;
+
+		List<List<Way>> cellWays = Util.getWaysInCell(w, _cellWays);
+		for( List<Way> ways : cellWays)
+		{
+			for( Way w2 : ways)
+			{
+				if( _errorWays.contains(w, w2) || _errorWays.contains(w2, w) )
+					continue;
+
+				String natural2 = w.get("natural");
+				if( natural2 == null || !natural2.equals("coastline") )
+					continue;
+
+				if( w.nodes.get(0).equals(w2.nodes.get(0)) || w.nodes.get(w.nodes.size() - 1).equals(w2.nodes.get(w2.nodes.size() - 1)))
+				{
+					List<OsmPrimitive> primitives = new ArrayList<OsmPrimitive>();
+					primitives.add(w);
+					primitives.add(w2);
+					errors.add( new TestError(this, Severity.ERROR, tr("Unordered coastline"), UNORDERED_COASTLINES, primitives) );
+					_errorWays.add(w, w2);
+				}
+			}
+			ways.add(w);
+		}
 	}
 }
Index: /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/CrossingWays.java
===================================================================
--- /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/CrossingWays.java	(revision 9683)
+++ /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/CrossingWays.java	(revision 9684)
@@ -14,9 +14,11 @@
 /**
  * Tests if there are segments that crosses in the same layer
- * 
+ *
  * @author frsantos
  */
-public class CrossingWays extends Test 
+public class CrossingWays extends Test
 {
+	protected static int CROSSING_WAYS = 601;
+
 	/** All way segments, grouped by cells */
 	Map<Point2D,List<ExtendedSegment>> cellSegments;
@@ -26,9 +28,9 @@
 	Map<List<Way>, List<WaySegment>> ways_seen;
 
-	
+
 	/**
 	 * Constructor
 	 */
-	public CrossingWays() 
+	public CrossingWays()
 	{
 		super(tr("Crossing ways."),
@@ -38,5 +40,5 @@
 
 	@Override
-	public void startTest() 
+	public void startTest()
 	{
 		cellSegments = new HashMap<Point2D,List<ExtendedSegment>>(1000);
@@ -46,5 +48,5 @@
 
 	@Override
-	public void endTest() 
+	public void endTest()
 	{
 		cellSegments = null;
@@ -54,17 +56,17 @@
 
 	@Override
-	public void visit(Way w) 
+	public void visit(Way w)
 	{
 		if( w.deleted || w.incomplete )
 			return;
 
-		String coastline1 = w.get("natural"); 
+		String coastline1 = w.get("natural");
 		boolean isCoastline1 = coastline1 != null && (coastline1.equals("water") || coastline1.equals("coastline"));
-		String railway1 = w.get("railway"); 
+		String railway1 = w.get("railway");
 		boolean isSubway1 = railway1 != null && railway1.equals("subway");
-		if( w.get("highway") == null && w.get("waterway") == null && (railway1 == null || isSubway1)  && !isCoastline1) 
+		if( w.get("highway") == null && w.get("waterway") == null && (railway1 == null || isSubway1)  && !isCoastline1)
 			return;
 
-	        String layer1 = w.get("layer");
+		String layer1 = w.get("layer");
 
 		int nodesSize = w.nodes.size();
@@ -102,7 +104,6 @@
 						highlight.add(es2.ws);
 
-						errors.add(new TestError(this, Severity.WARNING, tr("Crossing ways"),
-						prims,
-						highlight));
+						errors.add(new TestError(this, Severity.WARNING,
+						tr("Crossing ways"), CROSSING_WAYS, prims, highlight));
 						ways_seen.put(prims, highlight);
 					}
@@ -131,71 +132,71 @@
 		for( Point2D cell : Util.getSegmentCells(n1, n2, 10000) )
 		{
-            List<ExtendedSegment> segments = cellSegments.get( cell );
-            if( segments == null )
-            {
-                segments = new ArrayList<ExtendedSegment>();
-                cellSegments.put(cell, segments);
-            }
-            cells.add(segments);
-        }
-        
+			List<ExtendedSegment> segments = cellSegments.get( cell );
+			if( segments == null )
+			{
+				segments = new ArrayList<ExtendedSegment>();
+				cellSegments.put(cell, segments);
+			}
+			cells.add(segments);
+		}
+
 		return cells;
 	}
-    
-    /**
-     * A way segment with some additional information
-     * @author frsantos
-     */
-    private class ExtendedSegment
-    {
+
+	/**
+	 * A way segment with some additional information
+	 * @author frsantos
+	 */
+	private class ExtendedSegment
+	{
 		public Node n1, n2;
 
 		public WaySegment ws;
-        
-        /** The layer */
-        public String layer;
-        
-        /** The railway type */
+
+		/** The layer */
+		public String layer;
+
+		/** The railway type */
 		public String railway;
 
 		/** The coastline type */
 		public String coastline;
-        
-        /**
-         * Constructor
-         * @param ws The way segment
-         * @param layer The layer of the way this segment is in
-         * @param railway The railway type of the way this segment is in
-         * @param coastline The coastlyne typo of the way the segment is in
-         */
-        public ExtendedSegment(WaySegment ws, String layer, String railway, String coastline)
-        {
-            this.ws = ws;
+
+		/**
+		 * Constructor
+		 * @param ws The way segment
+		 * @param layer The layer of the way this segment is in
+		 * @param railway The railway type of the way this segment is in
+		 * @param coastline The coastlyne typo of the way the segment is in
+		 */
+		public ExtendedSegment(WaySegment ws, String layer, String railway, String coastline)
+		{
+			this.ws = ws;
 			this.n1 = ws.way.nodes.get(ws.lowerIndex);
 			this.n2 = ws.way.nodes.get(ws.lowerIndex + 1);
-            this.layer = layer;
-            this.railway = railway;
-            this.coastline = coastline;
-        }
-        
-        /**
-         * Checks whether this segment crosses other segment
-         * @param s2 The other segment
-         * @return true if both segements crosses
-         */
-        public boolean intersects(ExtendedSegment s2)
-        {
-			if( n1.equals(s2.n1) || n2.equals(s2.n2) ||  
-        		n1.equals(s2.n2)   || n2.equals(s2.n1) )
-        	{
-                return false;
-        	}
-            
-    		return Line2D.linesIntersect(
+			this.layer = layer;
+			this.railway = railway;
+			this.coastline = coastline;
+		}
+
+		/**
+		 * Checks whether this segment crosses other segment
+		 * @param s2 The other segment
+		 * @return true if both segements crosses
+		 */
+		public boolean intersects(ExtendedSegment s2)
+		{
+			if( n1.equals(s2.n1) || n2.equals(s2.n2) ||
+				n1.equals(s2.n2)   || n2.equals(s2.n1) )
+			{
+				return false;
+			}
+
+			return Line2D.linesIntersect(
 				n1.eastNorth.east(), n1.eastNorth.north(),
 				n2.eastNorth.east(), n2.eastNorth.north(),
 				s2.n1.eastNorth.east(), s2.n1.eastNorth.north(),
 				s2.n2.eastNorth.east(), s2.n2.eastNorth.north());
-        }
-    }
+		}
+	}
 }
Index: /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/DuplicateNode.java
===================================================================
--- /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/DuplicateNode.java	(revision 9683)
+++ /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/DuplicateNode.java	(revision 9684)
@@ -17,16 +17,18 @@
 /**
  * Tests if there are duplicate nodes
- * 
+ *
  * @author frsantos
  */
-public class DuplicateNode extends Test 
+public class DuplicateNode extends Test
 {
+	protected static int DUPLICATE_NODE = 1;
+
 	/** Bag of all nodes */
 	Bag<LatLon, OsmPrimitive> nodes;
-	
+
 	/**
 	 * Constructor
 	 */
-	public DuplicateNode() 
+	public DuplicateNode()
 	{
 		super(tr("Duplicated nodes."),
@@ -36,5 +38,5 @@
 
 	@Override
-	public void startTest() 
+	public void startTest()
 	{
 		nodes = new Bag<LatLon, OsmPrimitive>(1000);
@@ -42,5 +44,5 @@
 
 	@Override
-	public void endTest() 
+	public void endTest()
 	{
 		for(List<OsmPrimitive> duplicated : nodes.values() )
@@ -48,5 +50,5 @@
 			if( duplicated.size() > 1)
 			{
-				TestError testError = new TestError(this, Severity.ERROR, tr("Duplicated nodes"), duplicated);
+				TestError testError = new TestError(this, Severity.ERROR, tr("Duplicated nodes"), DUPLICATE_NODE, duplicated);
 				errors.add( testError );
 			}
@@ -56,64 +58,65 @@
 
 	@Override
-	public void visit(Node n) 
+	public void visit(Node n)
 	{
 		if(!n.deleted && !n.incomplete)
 			nodes.add(n.coor, n);
 	}
-	
-    /**
-     * Merge the nodes into one.
-     * Copied from UtilsPlugin.MergePointsAction
-     */
+
+	/**
+	 * Merge the nodes into one.
+	 * Copied from UtilsPlugin.MergePointsAction
+	 */
 	@Override
 	public Command fixError(TestError testError)
 	{
-        Collection<? extends OsmPrimitive> sel = testError.getPrimitives();
-        Collection<OsmPrimitive> nodes = new ArrayList<OsmPrimitive>();
-        
-        Node target = null;
-        for (OsmPrimitive osm : sel)
-            nodes.add(osm);
-        
-        if( nodes.size() < 2 )
-            return null;
-        
-        for ( OsmPrimitive o : nodes )
-        {
-            Node n = (Node)o;
-            if( target == null || target.id == 0 )
-            {
-                target = n;
-                continue;
-            }
-            if( n.id == 0 )
-                continue;
-            if( n.id < target.id )
-                target = n;
-        }
-        if( target == null )
-            return null;
-        
-        // target is what we're merging into
-        // nodes is the list of nodes to be removed
-        nodes.remove(target);
-        
-        // Merge all properties
-        Node newtarget = new Node(target);
-        for (final OsmPrimitive o : nodes) 
-        {
-            Node n = (Node)o;
-            for ( String key : n.keySet() )
-            {
-                if( newtarget.keySet().contains(key) && !newtarget.get(key).equals(n.get(key)) )
-                {
-                    JOptionPane.showMessageDialog(Main.parent, tr("Nodes have conflicting key: " + key + " ["+newtarget.get(key)+", "+n.get(key)+"]"));
-                    return null;
-                }
-                newtarget.put( key, n.get(key) ); 
-            }
-        }        
+		Collection<? extends OsmPrimitive> sel = testError.getPrimitives();
+		Collection<OsmPrimitive> nodes = new ArrayList<OsmPrimitive>();
 
-        Collection<Command> cmds = new LinkedList<Command>();
+		Node target = null;
+		for (OsmPrimitive osm : sel)
+			nodes.add(osm);
+
+		if( nodes.size() < 2 )
+			return null;
+
+		for ( OsmPrimitive o : nodes )
+		{
+			Node n = (Node)o;
+			if( target == null || target.id == 0 )
+			{
+				target = n;
+				continue;
+			}
+			if( n.id == 0 )
+				continue;
+			if( n.id < target.id )
+				target = n;
+		}
+		if( target == null )
+			return null;
+
+		// target is what we're merging into
+		// nodes is the list of nodes to be removed
+		nodes.remove(target);
+
+		// Merge all properties
+		Node newtarget = new Node(target);
+		for (final OsmPrimitive o : nodes)
+		{
+			Node n = (Node)o;
+			for ( String key : n.keySet() )
+			{
+				if( newtarget.keySet().contains(key) && !newtarget.get(key).equals(n.get(key)) )
+				{
+					JOptionPane.showMessageDialog(Main.parent, tr("Nodes have conflicting key: {0} [{1}, {2}]",
+					key, newtarget.get(key), n.get(key)));
+					return null;
+				}
+				newtarget.put( key, n.get(key) );
+			}
+		}
+
+		Collection<Command> cmds = new LinkedList<Command>();
 
 		// Now search the ways for occurences of the nodes we are about to
@@ -135,13 +138,13 @@
 		}
 
-        cmds.add(new DeleteCommand(nodes));
-        cmds.add(new ChangeCommand(target, newtarget));
-        return new SequenceCommand(tr("Merge Nodes"), cmds);
+		cmds.add(new DeleteCommand(nodes));
+		cmds.add(new ChangeCommand(target, newtarget));
+		return new SequenceCommand(tr("Merge Nodes"), cmds);
 	}
-	
+
 	@Override
 	public boolean isFixable(TestError testError)
 	{
 		return (testError.getTester() instanceof DuplicateNode);
-	}	
+	}
 }
Index: /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/DuplicatedWayNodes.java
===================================================================
--- /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/DuplicatedWayNodes.java	(revision 9683)
+++ /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/DuplicatedWayNodes.java	(revision 9684)
@@ -1,4 +1,6 @@
 package org.openstreetmap.josm.plugins.validator.tests;
+
 import static org.openstreetmap.josm.tools.I18n.tr;
+
 import org.openstreetmap.josm.plugins.validator.Test;
 import org.openstreetmap.josm.plugins.validator.TestError;
@@ -14,4 +16,6 @@
 
 public class DuplicatedWayNodes extends Test {
+	protected static int DUPLICATE_WAY_NODE = 501;
+
 	public DuplicatedWayNodes() {
 		super(tr("Duplicated way nodes."),
@@ -29,5 +33,5 @@
 			}
 			if (lastN == n) {
-				errors.add(new TestError(this, Severity.ERROR, tr("Duplicated way nodes"),
+				errors.add(new TestError(this, Severity.ERROR, tr("Duplicated way nodes"), DUPLICATE_WAY_NODE,
 					Arrays.asList(w), Arrays.asList(n)));
 				break;
Index: /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/NodesWithSameName.java
===================================================================
--- /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/NodesWithSameName.java	(revision 9683)
+++ /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/NodesWithSameName.java	(revision 9684)
@@ -14,10 +14,11 @@
 
 public class NodesWithSameName extends Test {
+	protected static int SAME_NAME = 801;
+
 	private Map<String, List<Node>> namesToNodes;
 
 	public NodesWithSameName() {
 		super(tr("Nodes with same name"),
-			tr("Find nodes that have the same name " +
-				"(might be duplicates due to e.g. the OpenGeoDB import)"));
+			tr("Find nodes that have the same name (might be duplicates)"));
 	}
 
@@ -43,5 +44,5 @@
 			if (nodes.size() > 1) {
 				errors.add(new TestError(this, Severity.WARNING,
-					tr("Nodes with same name"), nodes));
+					tr("Nodes with same name"), SAME_NAME, nodes));
 			}
 		}
Index: /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/OverlappingWays.java
===================================================================
--- /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/OverlappingWays.java	(revision 9683)
+++ /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/OverlappingWays.java	(revision 9684)
@@ -22,13 +22,19 @@
  * @author frsantos
  */
-public class OverlappingWays extends Test 
+public class OverlappingWays extends Test
 {
 	/** Bag of all way segments */
 	Bag<Pair<Node,Node>, WaySegment> nodePairs;
-	
-	/**
-	 * Constructor
-	 */
-	public OverlappingWays() 
+
+	protected static int OVERLAPPING_HIGHWAY = 101;
+	protected static int OVERLAPPING_RAILWAY = 102;
+	protected static int OVERLAPPING_WAY = 103;
+	protected static int OVERLAPPING_HIGHWAY_AREA = 111;
+	protected static int OVERLAPPING_RAILWAY_AREA = 112;
+	protected static int OVERLAPPING_WAY_AREA = 113;
+	protected static int OVERLAPPING_AREA = 120;
+
+	/** Constructor */
+	public OverlappingWays()
 	{
 		super(tr("Overlapping ways."),
@@ -46,8 +52,7 @@
 
 	@Override
-	public void endTest() 
+	public void endTest()
 	{
-		Map<List<Way>, List<WaySegment>> ways_seen = 
-                        new HashMap<List<Way>, List<WaySegment>>(500);
+		Map<List<Way>, List<WaySegment>> ways_seen = new HashMap<List<Way>, List<WaySegment>>(500);
 
 		for (List<WaySegment> duplicated : nodePairs.values())
@@ -84,29 +89,51 @@
 				/* These ways not seen before
 				 * If two or more of the overlapping ways are
- 				 * highways or railways mark a seperate error
-  				*/
+				 * highways or railways mark a seperate error
+				 */
 				if ((highlight = ways_seen.get(current_ways)) == null)
-                                {
+				{
 					String errortype;
+					int type;
 
 					if(area > 0)
 					{
 						if (ways == 0 || duplicated.size() == area)
+						{
 							errortype = tr("Overlapping areas");
+							type = OVERLAPPING_AREA;
+						}
 						else if (highway == ways)
+						{
 							errortype = tr("Overlapping highways (with area)");
+							type = OVERLAPPING_HIGHWAY_AREA;
+						}
 						else if (railway == ways)
+						{
 							errortype = tr("Overlapping railways (with area)");
+							type = OVERLAPPING_RAILWAY_AREA;
+						}
 						else
+						{
 							errortype = tr("Overlapping ways (with area)");
+							type = OVERLAPPING_WAY_AREA;
+						}
 					}
 					else if (highway == ways)
+					{
 						errortype = tr("Overlapping highways");
+						type = OVERLAPPING_HIGHWAY;
+					}
 					else if (railway == ways)
+					{
 						errortype = tr("Overlapping railways");
+						type = OVERLAPPING_RAILWAY;
+					}
 					else
+					{
 						errortype = tr("Overlapping ways");
+						type = OVERLAPPING_WAY;
+					}
 
-					errors.add(new TestError(this, Severity.OTHER, tr(errortype), prims, duplicated));
+					errors.add(new TestError(this, Severity.OTHER, tr(errortype), type, prims, duplicated));
 					ways_seen.put(current_ways, duplicated);
 				}
@@ -122,5 +149,5 @@
 
 	@Override
-	public void visit(Way w) 
+	public void visit(Way w)
 	{
 		Node lastN = null;
Index: /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/SelfIntersectingWay.java
===================================================================
--- /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/SelfIntersectingWay.java	(revision 9683)
+++ /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/SelfIntersectingWay.java	(revision 9684)
@@ -16,4 +16,6 @@
  */
 public class SelfIntersectingWay extends Test {
+	protected static int SELF_INTERSECT = 401;
+
 	public SelfIntersectingWay() {
 		super(tr("Self-intersecting ways"),
@@ -29,5 +31,5 @@
 			if (nodes.contains(n)) {
 				errors.add(new TestError(this,
-					Severity.WARNING, tr("Self-intersecting ways"),
+					Severity.WARNING, tr("Self-intersecting ways"), SELF_INTERSECT,
 					Arrays.asList(w), Arrays.asList(n)));
 				break;
@@ -36,4 +38,4 @@
 			}
 		}
-	}		
+	}
 }
Index: /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/SimilarNamedWays.java
===================================================================
--- /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/SimilarNamedWays.java	(revision 9683)
+++ /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/SimilarNamedWays.java	(revision 9684)
@@ -13,21 +13,24 @@
 import org.openstreetmap.josm.plugins.validator.util.Bag;
 import org.openstreetmap.josm.plugins.validator.util.Util;
+
 /**
  * Checks for similar named ways, symptom of a possible typo. It uses the
  * Levenshtein distance to check for similarity
- * 
+ *
  * @author frsantos
  */
-public class SimilarNamedWays extends Test 
+public class SimilarNamedWays extends Test
 {
-    /** All ways, grouped by cells */
-    Map<Point2D,List<Way>> cellWays;
-    /** The already detected errors */
-    Bag<Way, Way> errorWays;
-    
-    /**
+	protected static int SIMILAR_NAMED = 701;
+
+	/** All ways, grouped by cells */
+	Map<Point2D,List<Way>> cellWays;
+	/** The already detected errors */
+	Bag<Way, Way> errorWays;
+
+	/**
 	 * Constructor
 	 */
-	public SimilarNamedWays() 
+	public SimilarNamedWays()
 	{
 		super(tr("Similar named ways."),
@@ -35,133 +38,132 @@
 	}
 
-    @Override
-    public void startTest() 
-    {
-        cellWays = new HashMap<Point2D,List<Way>>(1000);
-        errorWays = new Bag<Way, Way>();
-    }
+	@Override
+	public void startTest()
+	{
+		cellWays = new HashMap<Point2D,List<Way>>(1000);
+		errorWays = new Bag<Way, Way>();
+	}
 
-    @Override
-    public void endTest() 
-    {
-        cellWays = null;
-        errorWays = null;
-    }
-    
 	@Override
-	public void visit(Way w) 
+	public void endTest()
 	{
-        if( w.deleted || w.incomplete )
-            return;
-        
-        String name = w.get("name");
-        if( name == null || name.length() < 6 )
-            return;
-        
-        List<List<Way>> theCellWays = Util.getWaysInCell(w, cellWays);
-        for( List<Way> ways : theCellWays)
-        {
-            for( Way w2 : ways)
-            {
-                if( errorWays.contains(w, w2) || errorWays.contains(w2, w) )
-                	continue;
-                
-                String name2 = w2.get("name");
-                if( name2 == null || name2.length() < 6 )
-                    continue;
-                
-                int levenshteinDistance = getLevenshteinDistance(name, name2);
-                if( 0 < levenshteinDistance && levenshteinDistance <= 2 )
-                {
-                    List<OsmPrimitive> primitives = new ArrayList<OsmPrimitive>();
-                    primitives.add(w);
-                    primitives.add(w2);
-                    errors.add( new TestError(this, Severity.WARNING, tr("Similar named ways"), primitives) );
-                    errorWays.add(w, w2);
-                }
-            }
-            ways.add(w);
-        }
+		cellWays = null;
+		errorWays = null;
 	}
-    
-    /**
-     * Compute Levenshtein distance
-     * 
-     * @param s First word
-     * @param t Second word
-     * @return The distance between words
-     */
-    public int getLevenshteinDistance(String s, String t)
-    {
-        int d[][]; // matrix
-        int n; // length of s
-        int m; // length of t
-        int i; // iterates through s
-        int j; // iterates through t
-        char s_i; // ith character of s
-        char t_j; // jth character of t
-        int cost; // cost
 
-        // Step 1
+	@Override
+	public void visit(Way w)
+	{
+		if( w.deleted || w.incomplete )
+			return;
 
-        n = s.length();
-        m = t.length();
-        if (n == 0) return m;
-        if (m == 0) return n;
-        d = new int[n + 1][m + 1];
+		String name = w.get("name");
+		if( name == null || name.length() < 6 )
+			return;
 
-        // Step 2
-        for (i = 0; i <= n; i++) d[i][0] = i;
-        for (j = 0; j <= m; j++) d[0][j] = j;
+		List<List<Way>> theCellWays = Util.getWaysInCell(w, cellWays);
+		for( List<Way> ways : theCellWays)
+		{
+			for( Way w2 : ways)
+			{
+				if( errorWays.contains(w, w2) || errorWays.contains(w2, w) )
+					continue;
 
-        // Step 3
-        for (i = 1; i <= n; i++)
-        {
-            s_i = s.charAt(i - 1);
+				String name2 = w2.get("name");
+				if( name2 == null || name2.length() < 6 )
+					continue;
 
-            // Step 4
-            for (j = 1; j <= m; j++)
-            {
-                t_j = t.charAt(j - 1);
+				int levenshteinDistance = getLevenshteinDistance(name, name2);
+				if( 0 < levenshteinDistance && levenshteinDistance <= 2 )
+				{
+					List<OsmPrimitive> primitives = new ArrayList<OsmPrimitive>();
+					primitives.add(w);
+					primitives.add(w2);
+					errors.add( new TestError(this, Severity.WARNING, tr("Similar named ways"), SIMILAR_NAMED, primitives) );
+					errorWays.add(w, w2);
+				}
+			}
+			ways.add(w);
+		}
+	}
 
-                // Step 5
-                if (s_i == t_j)
-                {
-                    cost = 0;
-                }
-                else
-                {
-                    cost = 1;
-                }
+	/**
+	 * Compute Levenshtein distance
+	 *
+	 * @param s First word
+	 * @param t Second word
+	 * @return The distance between words
+	 */
+	public int getLevenshteinDistance(String s, String t)
+	{
+		int d[][]; // matrix
+		int n; // length of s
+		int m; // length of t
+		int i; // iterates through s
+		int j; // iterates through t
+		char s_i; // ith character of s
+		char t_j; // jth character of t
+		int cost; // cost
 
-                // Step 6
-                d[i][j] = Minimum(d[i - 1][j] + 1, d[i][j - 1] + 1, d[i - 1][j - 1] + cost);
-            }
-        }
+		// Step 1
 
-        // Step 7
-        return d[n][m];
+		n = s.length();
+		m = t.length();
+		if (n == 0) return m;
+		if (m == 0) return n;
+		d = new int[n + 1][m + 1];
 
-    }
+		// Step 2
+		for (i = 0; i <= n; i++) d[i][0] = i;
+		for (j = 0; j <= m; j++) d[0][j] = j;
 
-    /**
-     * Get minimum of three values
-     * @param a First value
-     * @param b Second value
-     * @param c Third value
-     * @return The minimum of the tre values
-     */
-    private static int Minimum(int a, int b, int c)
-    {
-        int mi = a;
-        if (b < mi)
-        {
-            mi = b;
-        }
-        if (c < mi)
-        {
-            mi = c;
-        }
-        return mi;
-    }
+		// Step 3
+		for (i = 1; i <= n; i++)
+		{
+			s_i = s.charAt(i - 1);
+
+			// Step 4
+			for (j = 1; j <= m; j++)
+			{
+				t_j = t.charAt(j - 1);
+
+				// Step 5
+				if (s_i == t_j)
+				{
+					cost = 0;
+				}
+				else
+				{
+					cost = 1;
+				}
+
+				// Step 6
+				d[i][j] = Minimum(d[i - 1][j] + 1, d[i][j - 1] + 1, d[i - 1][j - 1] + cost);
+			}
+		}
+
+		// Step 7
+		return d[n][m];
+	}
+
+	/**
+	 * Get minimum of three values
+	 * @param a First value
+	 * @param b Second value
+	 * @param c Third value
+	 * @return The minimum of the tre values
+	 */
+	private static int Minimum(int a, int b, int c)
+	{
+		int mi = a;
+		if (b < mi)
+		{
+			mi = b;
+		}
+		if (c < mi)
+		{
+			mi = c;
+		}
+		return mi;
+	}
 }
Index: /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/TagChecker.java
===================================================================
--- /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/TagChecker.java	(revision 9683)
+++ /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/TagChecker.java	(revision 9684)
@@ -112,10 +112,11 @@
 	protected JButton deleteSrcButton;
 
-	protected static int EMPTY_VALUES = 0;
-	protected static int INVALID_KEY = 1;
-	protected static int INVALID_VALUE = 2;
-	protected static int FIXME = 3;
-	protected static int INVALID_SPACE = 3;
-	protected static int TAG_CHECK = 4;
+	protected static int EMPTY_VALUES      = 1200;
+	protected static int INVALID_KEY       = 1201;
+	protected static int INVALID_VALUE     = 1202;
+	protected static int FIXME             = 1203;
+	protected static int INVALID_SPACE     = 1204;
+	protected static int INVALID_KEY_SPACE = 1205;
+	protected static int TAG_CHECK         = 1206;
 
 	/** List of sources for spellcheck data */
@@ -165,5 +166,5 @@
 				sources = SPELL_FILE + ";" + sources;
 		}
-		
+
 		StringTokenizer st = new StringTokenizer(sources, ";");
 		StringBuilder errorSources = new StringBuilder();
@@ -224,5 +225,5 @@
 			throw new IOException( tr("Could not download data file(s):\n{0}", errorSources) );
 	}
-	
+
 	/**
 	 * Reads the presets data.
@@ -245,6 +246,6 @@
 		readPresetFromPreferences();
 	}
-	
-	
+
+
 	@Override
 	public void visit(Node n)
@@ -275,5 +276,6 @@
 				if(d.match(p))
 				{
-					errors.add( new TestError(this, Severity.WARNING, tr("Illegal tag/value combinations"), p, TAG_CHECK) );
+					errors.add( new TestError(this, Severity.WARNING, tr("Illegal tag/value combinations"),
+					tr(d.description()), TAG_CHECK, p) );
 					withErrors.add(p, "TC");
 					break;
@@ -289,20 +291,24 @@
 			if( checkValues && (value==null || value.trim().length() == 0) && !withErrors.contains(p, "EV"))
 			{
-				errors.add( new TestError(this, Severity.WARNING, tr("Tags with empty values"), tr("Key ''{0}'' invalid.", key), p, EMPTY_VALUES) );
+				errors.add( new TestError(this, Severity.WARNING, tr("Tags with empty values"),
+				tr("Key ''{0}'' invalid.", key), EMPTY_VALUES, p) );
 				withErrors.add(p, "EV");
 			}
 			if( checkKeys && spellCheckKeyData.containsKey(key) && !withErrors.contains(p, "IPK"))
 			{
-				errors.add( new TestError(this, Severity.WARNING, tr("Invalid property key"), tr("Key ''{0}'' invalid.", key), p, INVALID_KEY) );
+				errors.add( new TestError(this, Severity.WARNING, tr("Invalid property key"),
+				tr("Key ''{0}'' invalid.", key), INVALID_KEY, p) );
 				withErrors.add(p, "IPK");
 			}
 			if( checkKeys && key.indexOf(" ") >= 0 && !withErrors.contains(p, "IPK"))
 			{
-				errors.add( new TestError(this, Severity.WARNING, tr("Invalid white space in property key"), tr("Key ''{0}'' invalid.", key), p, INVALID_KEY) );
+				errors.add( new TestError(this, Severity.WARNING, tr("Invalid white space in property key"),
+				tr("Key ''{0}'' invalid.", key), INVALID_KEY_SPACE, p) );
 				withErrors.add(p, "IPK");
 			}
 			if( checkValues && value != null && (value.startsWith(" ") || value.endsWith(" ")) && !withErrors.contains(p, "SPACE"))
 			{
-				errors.add( new TestError(this, Severity.OTHER, tr("Property values start or end with white space"), tr("Key ''{0}'' invalid.", key), p, INVALID_SPACE) );
+				errors.add( new TestError(this, Severity.OTHER, tr("Property values start or end with white space"),
+				tr("Key ''{0}'' invalid.", key), INVALID_SPACE, p) );
 				withErrors.add(p, "SPACE");
 			}
@@ -312,5 +318,6 @@
 				if( values != null && !values.contains(prop.getValue()) && !withErrors.contains(p, "UPV"))
 				{
-					errors.add( new TestError(this, Severity.OTHER, tr("Unknown property values"), tr("Key ''{0}'' invalid.", key), p, INVALID_VALUE) );
+					errors.add( new TestError(this, Severity.OTHER, tr("Unknown property values"),
+					tr("Key ''{0}'' invalid.", key), INVALID_VALUE, p) );
 					withErrors.add(p, "UPV");
 				}
@@ -321,5 +328,5 @@
 				&& !withErrors.contains(p, "FIXME"))
 				{
-					errors.add( new TestError(this, Severity.OTHER, tr("FIXMES"), p, FIXME) );
+					errors.add( new TestError(this, Severity.OTHER, tr("FIXMES"), FIXME, p) );
 					withErrors.add(p, "FIXME");
 				}
@@ -346,5 +353,5 @@
 			in = new BufferedReader(new InputStreamReader(inStream));
 		}
-		
+
 		XmlObjectParser parser = new XmlObjectParser();
 		parser.mapOnStart("item", TaggingPreset.class);
@@ -355,5 +362,5 @@
 		parser.map("key", TaggingPreset.Key.class);
 		parser.start(in);
-		
+
 		while(parser.hasNext())
 		{
@@ -378,5 +385,5 @@
 			InputStream in = null;
 			String source = st.nextToken();
-			try 
+			try
 			{
 				if (source.startsWith("http") || source.startsWith("ftp") || source.startsWith("file"))
@@ -388,9 +395,9 @@
 				readPresets(in);
 				in.close();
-			} 
+			}
 			catch (IOException e)
 			{
 				// Error already reported by JOSM
-			} 
+			}
 			catch (SAXException e)
 			{
@@ -426,5 +433,5 @@
 			super.visit(selection);
 	}
-	
+
 	@Override
 	public void addGui(JPanel testPanel)
@@ -575,5 +582,6 @@
 	{
 		enabled = prefCheckKeys.isSelected() || prefCheckValues.isSelected() || prefCheckComplex.isSelected() || prefCheckFixmes.isSelected();
-		testBeforeUpload = prefCheckKeysBeforeUpload.isSelected() || prefCheckValuesBeforeUpload.isSelected() || prefCheckFixmesBeforeUpload.isSelected() || prefCheckComplexBeforeUpload.isSelected();
+		testBeforeUpload = prefCheckKeysBeforeUpload.isSelected() || prefCheckValuesBeforeUpload.isSelected()
+		|| prefCheckFixmesBeforeUpload.isSelected() || prefCheckComplexBeforeUpload.isSelected();
 
 		Main.pref.put(PREF_CHECK_VALUES, prefCheckValues.isSelected());
@@ -620,4 +628,8 @@
 				else if(value.startsWith(" ") || value.endsWith(" "))
 					commands.add( new ChangePropertyCommand(Collections.singleton(primitives.get(i)), key, value.trim()) );
+				else if(key.startsWith(" ") || key.endsWith(" "))
+				{
+					commands.add( new ChangePropertyKeyCommand(Collections.singleton(primitives.get(i)), key, key.trim()) );
+				}
 				else
 				{
@@ -642,6 +654,6 @@
 		if( testError.getTester() instanceof TagChecker)
 		{
-			int code = testError.getInternalCode();
-			return code == INVALID_KEY || code == EMPTY_VALUES || code == INVALID_SPACE;
+			int code = testError.getCode();
+			return code == INVALID_KEY || code == EMPTY_VALUES || code == INVALID_SPACE || code == INVALID_KEY_SPACE;
 		}
 
@@ -652,5 +664,4 @@
 		public String getData(String data)
 		{
-System.out.println(data);
 			return "not implemented yet";
 		}
@@ -659,4 +670,8 @@
 			return false;
 		}
+		public String description()
+		{
+			return "not implemented yet";
+		}
 	}
 }
Index: /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/UnclosedWays.java
===================================================================
--- /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/UnclosedWays.java	(revision 9683)
+++ /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/UnclosedWays.java	(revision 9684)
@@ -18,5 +18,5 @@
  * @author stoecker
  */
-public class UnclosedWays extends Test  {
+public class UnclosedWays extends Test	{
 	/** The already detected errors */
 	Bag<Way, Way> _errorWays;
@@ -42,5 +42,5 @@
 		_errorWays = null;
 	}
-	
+
 	@Override
 	public void visit(Way w)
@@ -48,8 +48,9 @@
 		boolean force = false; /* force even if end-to-end distance is long */
 		String type = null, test;
-		
+		int mode = 0;
+
 		if( w.deleted || w.incomplete )
 			return;
-		
+
 		test = w.get("natural");
 		if(test != null)
@@ -58,4 +59,5 @@
 				force = true;
 			type = tr("natural type {0}", tr(test));
+			mode = 1101;
 		}
 		test = w.get("landuse");
@@ -64,4 +66,5 @@
 			force = true;
 			type = tr("landuse type {0}", tr(test));
+			mode = 1102;
 		}
 		test = w.get("amenities");
@@ -70,4 +73,5 @@
 			force = true;
 			type = tr("amenities type {0}", tr(test));
+			mode = 1103;
 		}
 		test = w.get("sport");
@@ -76,4 +80,5 @@
 			force = true;
 			type = tr("sport type {0}", tr(test));
+			mode = 1104;
 		}
 		test = w.get("tourism");
@@ -82,4 +87,5 @@
 			force = true;
 			type = tr("tourism type {0}", tr(test));
+			mode = 1105;
 		}
 		test = w.get("shop");
@@ -88,4 +94,5 @@
 			force = true;
 			type = tr("shop type {0}", tr(test));
+			mode = 1106;
 		}
 		test = w.get("leisure");
@@ -94,4 +101,5 @@
 			force = true;
 			type = tr("leisure type {0}", tr(test));
+			mode = 1107;
 		}
 		test = w.get("waterway");
@@ -100,11 +108,6 @@
 			force = true;
 			type = tr("waterway type {0}", tr(test));
+			mode = 1108;
 		}
-		/*test = w.get("junction");
-		if(test != null && test.equals("roundabout"))
-		{
-			force = true;
-			type = tr("junction type {0}", tr(test));
-		}*/
 		test = w.get("building");
 		if (test != null && ("true".equalsIgnoreCase(test) || "yes".equalsIgnoreCase(test) || "1".equals(test)))
@@ -112,4 +115,5 @@
 			force = true;
 			type = tr("building");
+			mode = 1120;
 		}
 		test = w.get("area");
@@ -118,4 +122,5 @@
 			force = true;
 			type = tr("area");
+			mode = 1130;
 		}
 
@@ -129,5 +134,5 @@
 				List<OsmPrimitive> primitives = new ArrayList<OsmPrimitive>();
 				primitives.add(w);
-				errors.add(new TestError(this, Severity.WARNING, tr("Unclosed way"), type, primitives));
+				errors.add(new TestError(this, Severity.WARNING, tr("Unclosed way"), type, mode, primitives));
 				_errorWays.add(w,w);
 			}
Index: /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/UntaggedNode.java
===================================================================
--- /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/UntaggedNode.java	(revision 9683)
+++ /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/UntaggedNode.java	(revision 9684)
@@ -13,22 +13,23 @@
 import org.openstreetmap.josm.plugins.validator.Severity;
 import org.openstreetmap.josm.plugins.validator.Test;
+import org.openstreetmap.josm.plugins.validator.util.Util;
 import org.openstreetmap.josm.plugins.validator.TestError;
+
 /**
  * Checks for untagged nodes that are in no way
- * 
+ *
  * @author frsantos
  */
-public class UntaggedNode extends Test 
+public class UntaggedNode extends Test
 {
-	/** Tags allowed in a node */
-	public static String[] allowedTags = new String[] { "created_by" };
-	
+	protected static int UNTAGGED_NODE = 201;
+
 	/** Bag of all nodes */
 	Set<Node> emptyNodes;
-	
+
 	/**
 	 * Constructor
 	 */
-	public UntaggedNode() 
+	public UntaggedNode()
 	{
 		super(tr("Untagged nodes."),
@@ -37,12 +38,12 @@
 
 	@Override
-	public void startTest() 
+	public void startTest()
 	{
 		emptyNodes = new HashSet<Node>(100);
 	}
-	
+
 	@Override
-    public void visit(Collection<OsmPrimitive> selection) 
-    {
+	public void visit(Collection<OsmPrimitive> selection)
+	{
 		// If there is a partial selection, it may be false positives if a
 		// node is selected, but not the container way. So, in this
@@ -64,28 +65,15 @@
 			}
 		}
-    }
-    
+	}
+
 	@Override
-	public void visit(Node n) 
+	public void visit(Node n)
 	{
-		if (n.incomplete || n.deleted) return;
+		if(!n.incomplete && !n.deleted && Util.countDataTags(n) == 0)
+			emptyNodes.add(n);
+	}
 
-		int numTags = 0;
-		Map<String, String> tags = n.keys;
-		if( tags != null )
-		{
-			numTags = tags.size();
-			for( String tag : allowedTags)
-				if( tags.containsKey(tag) ) numTags--;
-		}
-		
-		if( numTags == 0 )
-		{
-			emptyNodes.add(n);
-		}
-	}
-	
 	@Override
-	public void visit(Way w) 
+	public void visit(Way w)
 	{
 		for (Node n : w.nodes) {
@@ -93,15 +81,15 @@
 		}
 	}
-	
+
 	@Override
-	public void endTest() 
+	public void endTest()
 	{
 		for(Node node : emptyNodes)
 		{
-			errors.add( new TestError(this, Severity.OTHER, tr("Untagged and unconnected nodes"), node) );
+			errors.add( new TestError(this, Severity.OTHER, tr("Untagged and unconnected nodes"), UNTAGGED_NODE, node) );
 		}
 		emptyNodes = null;
 	}
-	
+
 	@Override
 	public Command fixError(TestError testError)
@@ -109,9 +97,9 @@
 		return new DeleteCommand(testError.getPrimitives());
 	}
-	
+
 	@Override
 	public boolean isFixable(TestError testError)
 	{
 		return (testError.getTester() instanceof UntaggedNode);
-	}		
+	}
 }
Index: /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/UntaggedWay.java
===================================================================
--- /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/UntaggedWay.java	(revision 9683)
+++ /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/UntaggedWay.java	(revision 9684)
@@ -13,40 +13,39 @@
 import org.openstreetmap.josm.plugins.validator.Test;
 import org.openstreetmap.josm.plugins.validator.TestError;
+import org.openstreetmap.josm.plugins.validator.util.Util;
+
 /**
  * Checks for untagged ways
- * 
+ *
  * @author frsantos
  */
-public class UntaggedWay extends Test 
+public class UntaggedWay extends Test
 {
 	/** Empty way error */
-	protected static final int EMPTY_WAY 	= 0;
+	protected static final int EMPTY_WAY    = 301;
 	/** Untagged way error */
-	protected static final int UNTAGGED_WAY = 1;
+	protected static final int UNTAGGED_WAY = 302;
 	/** Unnamed way error */
-	protected static final int UNNAMED_WAY  = 2;
+	protected static final int UNNAMED_WAY  = 303;
 	/** One node way error */
-	protected static final int ONE_NODE_WAY = 3;
+	protected static final int ONE_NODE_WAY = 304;
 
-    /** Tags allowed in a way */
-    public static final String[] ALLOWED_TAGS = new String[] { "created_by", "converted_by" };
+	/** Ways that must have a name */
+	public static final Set<String> NAMED_WAYS = new HashSet<String>();
+	static
+	{
+		NAMED_WAYS.add( "motorway" );
+		NAMED_WAYS.add( "trunk" );
+		NAMED_WAYS.add( "primary" );
+		NAMED_WAYS.add( "secondary" );
+		NAMED_WAYS.add( "tertiary" );
+		NAMED_WAYS.add( "residential" );
+		NAMED_WAYS.add( "pedestrian" ); ;
+	}
 
-    /** Ways that must have a name */
-    public static final Set<String> NAMED_WAYS = new HashSet<String>();
-    static
-    {
-        NAMED_WAYS.add( "motorway" ); 
-        NAMED_WAYS.add( "trunk" ); 
-        NAMED_WAYS.add( "primary" ); 
-        NAMED_WAYS.add( "secondary" ); 
-        NAMED_WAYS.add( "tertiary" ); 
-        NAMED_WAYS.add( "residential" ); 
-        NAMED_WAYS.add( "pedestrian" ); ;
-    }
-    
-    /**
+	/**
 	 * Constructor
 	 */
-	public UntaggedWay() 
+	public UntaggedWay()
 	{
 		super(tr("Untagged, empty, and one node ways."),
@@ -55,52 +54,46 @@
 
 	@Override
-	public void visit(Way w) 
+	public void visit(Way w)
 	{
 		if (w.deleted || w.incomplete) return;
 
-		int numTags = 0;
 		Map<String, String> tags = w.keys;
 		if( tags != null )
 		{
-			numTags = tags.size();
-			for( String tag : ALLOWED_TAGS)
-				if( tags.containsKey(tag) ) numTags--;
-            
-            String highway = tags.get("highway");
-            if( numTags != 0 && highway != null && NAMED_WAYS.contains(highway))
-            {
-                if( !tags.containsKey("name") && !tags.containsKey("ref") )
-                {
-                    boolean hasName = false;
-                    for( String key : w.keySet())
-                    {
-                        hasName = key.startsWith("name:") || key.endsWith("_name") || key.endsWith("_ref");
-                        if( hasName )
-                            break;
-                    }
-                    
-                    if( !hasName)
-                        errors.add( new TestError(this, Severity.WARNING, tr("Unnamed ways"), w, UNNAMED_WAY ) );
-                }
-            }
+			String highway = tags.get("highway");
+			if(highway != null && NAMED_WAYS.contains(highway))
+			{
+				if( !tags.containsKey("name") && !tags.containsKey("ref") )
+				{
+					boolean hasName = false;
+					for( String key : w.keySet())
+					{
+						hasName = key.startsWith("name:") || key.endsWith("_name") || key.endsWith("_ref");
+						if( hasName )
+							break;
+					}
+
+					if( !hasName)
+						errors.add( new TestError(this, Severity.WARNING, tr("Unnamed ways"), UNNAMED_WAY, w) );
+				}
+			}
 		}
-		
-        if( numTags == 0 )
-        {
-            errors.add( new TestError(this, Severity.WARNING, tr("Untagged ways"), w, UNTAGGED_WAY) );
-        }
-        
-        if( w.nodes.size() == 0 )
-        {
-            errors.add( new TestError(this, Severity.ERROR, tr("Empty ways"), w, EMPTY_WAY) );
-        }
-        
-        if( w.nodes.size() == 1 )
-        {
-            errors.add( new TestError(this, Severity.ERROR, tr("One node ways"), w, ONE_NODE_WAY) );
-        }
-        
-	}		
-	
+
+		if(Util.countDataTags(w) == 0)
+		{
+			errors.add( new TestError(this, Severity.WARNING, tr("Untagged ways"), UNTAGGED_WAY, w) );
+		}
+
+		if( w.nodes.size() == 0 )
+		{
+			errors.add( new TestError(this, Severity.ERROR, tr("Empty ways"), EMPTY_WAY, w) );
+		}
+		else if( w.nodes.size() == 1 )
+		{
+			errors.add( new TestError(this, Severity.ERROR, tr("One node ways"), ONE_NODE_WAY, w) );
+		}
+
+	}
+
 	@Override
 	public boolean isFixable(TestError testError)
@@ -108,11 +101,11 @@
 		if( testError.getTester() instanceof UntaggedWay )
 		{
-			return testError.getInternalCode() == EMPTY_WAY
-				|| testError.getInternalCode() == ONE_NODE_WAY;
+			return testError.getCode() == EMPTY_WAY
+				|| testError.getCode() == ONE_NODE_WAY;
 		}
-		
+
 		return false;
 	}
-	
+
 	@Override
 	public Command fixError(TestError testError)
Index: /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/WronglyOrderedWays.java
===================================================================
--- /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/WronglyOrderedWays.java	(revision 9683)
+++ /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/WronglyOrderedWays.java	(revision 9684)
@@ -20,4 +20,8 @@
  */
 public class WronglyOrderedWays extends Test  {
+	protected static int WRONGLY_ORDERED_COAST = 1001;
+	protected static int WRONGLY_ORDERED_WATER = 1002;
+	protected static int WRONGLY_ORDERED_LAND  = 1003;
+
 	/** The already detected errors */
 	Bag<Way, Way> _errorWays;
@@ -43,23 +47,33 @@
 		_errorWays = null;
 	}
-	
+
 	@Override
 	public void visit(Way w)
 	{
 		String errortype = "";
-		
+		int type;
+
 		if( w.deleted || w.incomplete )
 			return;
-		
+
 		String natural = w.get("natural");
 		if( natural == null)
 			return;
-		
+
 		if( natural.equals("coastline") )
+		{
 			errortype = tr("Reversed coastline: land not on left side");
+			type= WRONGLY_ORDERED_COAST;
+		}
 		else if(natural.equals("water") )
+		{
 			errortype = tr("Reversed water: land not on left side");
+			type= WRONGLY_ORDERED_WATER;
+		}
 		else if( natural.equals("land") )
+		{
 			errortype = tr("Reversed land: land not on left side");
+			type= WRONGLY_ORDERED_LAND;
+		}
 		else
 			return;
@@ -90,5 +104,5 @@
 				List<OsmPrimitive> primitives = new ArrayList<OsmPrimitive>();
 				primitives.add(w);
-				errors.add( new TestError(this, Severity.WARNING, errortype, primitives) );
+				errors.add( new TestError(this, Severity.WARNING, errortype, type, primitives) );
 				_errorWays.add(w,w);
 			}
Index: /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/util/Util.java
===================================================================
--- /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/util/Util.java	(revision 9683)
+++ /applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/util/Util.java	(revision 9684)
@@ -15,4 +15,5 @@
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.Node;
 import org.openstreetmap.josm.plugins.*;
@@ -22,12 +23,28 @@
 /**
  * Utility class
- * 
+ *
  * @author frsantos
  */
-public class Util 
+public class Util
 {
-	/** 
+	/** Tags without informational contents */
+	private static final String[] noDataTags = new String[] { "created_by", "converted_by", "source" };
+	public static int countDataTags(OsmPrimitive osm)
+	{
+		int numTags = 0;
+		Map<String, String> tags = osm.keys;
+		if(tags != null)
+		{
+			numTags = tags.size();
+			for(String tag : noDataTags)
+				if(tags.containsKey(tag))
+					--numTags;
+		}
+		return numTags;
+	}
+
+	/**
 	 * Returns the plugin's directory of the plugin
-	 * 
+	 *
 	 * @return The directory of the plugin
 	 */
@@ -42,52 +59,52 @@
 	 */
 	public static Version getVersion()
-    {
-        PluginInformation info = PluginInformation.getLoaded("validator");
-        if( info == null )
-            return null;
+	{
+		PluginInformation info = PluginInformation.getLoaded("validator");
+		if( info == null )
+			return null;
 
 		return new Version(info.version, info.attr.get("Plugin-Date"));
-    }
-
-    /**
-     * Utility class for displaying versions
-     * 
-     * @author frsantos
-     */
-    public static class Version
-    {
-    	/** The revision */
-    	public String revision;
-    	/** The build time */
-    	public String time;
-    	
-        /**
-         * Constructor
-         * @param revision
-         * @param time
-         */
-        public Version(String revision, String time) 
-        {
+	}
+
+	/**
+	 * Utility class for displaying versions
+	 *
+	 * @author frsantos
+	 */
+	public static class Version
+	{
+		/** The revision */
+		public String revision;
+		/** The build time */
+		public String time;
+
+		/**
+		 * Constructor
+		 * @param revision
+		 * @param time
+		 */
+		public Version(String revision, String time)
+		{
 			this.revision = revision;
 			this.time = time;
 		}
-    }
-    
-    
-    /**
-     * Loads a text file in a String
-     * 
-     * @param resource The URL of the file
-     * @return A String with the file contents
-     * @throws IOException when error reading the file
-     */
-    public static String loadFile(URL resource) throws IOException
-    {
-    	BufferedReader in = null;
-		try 
+	}
+
+
+	/**
+	 * Loads a text file in a String
+	 *
+	 * @param resource The URL of the file
+	 * @return A String with the file contents
+	 * @throws IOException when error reading the file
+	 */
+	public static String loadFile(URL resource) throws IOException
+	{
+		BufferedReader in = null;
+		try
 		{
 			in = new BufferedReader(new InputStreamReader(resource.openStream()));
 			StringBuilder sb = new StringBuilder();
-			for (String line = in.readLine(); line != null; line = in.readLine()) 
+			for (String line = in.readLine(); line != null; line = in.readLine())
 			{
 				sb.append(line);
@@ -107,182 +124,182 @@
 			}
 		}
-    }
-    
-    /**
-     * Mirrors a file to a local file.
-     * <p>
-     * The file mirrored is only downloaded if it has been more than one day since last download
-     * 
-     * @param url The URL of the remote file
-     * @param destDir The destionation dir of the mirrored file
-     * @param maxTime The time interval, in seconds, to check if the file changed. If less than 0, it defaults to 1 week 
-     * @return The local file
-     */
-    public static File mirror(URL url, String destDir, long maxTime)
-    {
-        if( url.getProtocol().equals("file") )
-            return new File(url.toString() ) ;
-        
-        String localPath = Main.pref.get( PreferenceEditor.PREFIX + ".mirror." + url);
-        File oldFile = null;
-        if( localPath != null && localPath.length() > 0)
-        {
-            StringTokenizer st = new StringTokenizer(localPath, ";");
-            long checkDate = Long.parseLong(st.nextToken());
-            localPath = st.nextToken();
-            oldFile = new File(localPath);
-            maxTime = (maxTime <= 0) ? 7 * 24 * 60 * 60 * 1000 : maxTime * 1000;
-            if( System.currentTimeMillis() - checkDate < maxTime )
-            {
-                if( oldFile.exists() )
-                    return oldFile;
-            }
-        }
-
-        File destDirFile = new File(destDir);
-        if( !destDirFile.exists() )
-            destDirFile.mkdirs();
-
-        localPath = destDir + System.currentTimeMillis() + "-" + new File(url.getPath()).getName();
-        BufferedOutputStream bos = null;
-        BufferedInputStream bis = null;
-        try 
-        {
-            URLConnection conn = url.openConnection();
-            conn.setConnectTimeout(5000);
-            bis = new BufferedInputStream(conn.getInputStream());
-            bos = new BufferedOutputStream( new FileOutputStream(localPath) );
-            byte[] buffer = new byte[4096];
-            int length;
-            while( (length = bis.read( buffer )) > -1 )
-            {
-                bos.write( buffer, 0, length );
-            }
-        }
-        catch(IOException ioe)
-        {
-            if( oldFile != null )
-                return oldFile;
-            else
-                return null;
-        }
-        finally
-        {
-            if( bis != null )
-            {
-                try {
-                    bis.close();
-                } catch (IOException e) {
-                    e.printStackTrace();
-                }
-            }
-            if( bos != null )
-            {
-                try {
-                    bos.close();
-                } catch (IOException e) {
-                    e.printStackTrace();
-                }
-            }
-        }
-        
-        Main.pref.put( PreferenceEditor.PREFIX + ".mirror." + url, System.currentTimeMillis() + ";" + localPath);
-        
-        if( oldFile != null )
-            oldFile.delete();
-
-        return new File(localPath);
-    }
-    
-    /**
-     * Returns the start and end cells of a way.
-     * @param w The way
-     * @param cellWays The map with all cells
-     * @return A list with all the cells the way starts or ends
-     */
-    public static List<List<Way>> getWaysInCell(Way w, Map<Point2D,List<Way>> cellWays)
-    {
+	}
+
+	/**
+	 * Mirrors a file to a local file.
+	 * <p>
+	 * The file mirrored is only downloaded if it has been more than one day since last download
+	 *
+	 * @param url The URL of the remote file
+	 * @param destDir The destionation dir of the mirrored file
+	 * @param maxTime The time interval, in seconds, to check if the file changed. If less than 0, it defaults to 1 week
+	 * @return The local file
+	 */
+	public static File mirror(URL url, String destDir, long maxTime)
+	{
+		if( url.getProtocol().equals("file") )
+			return new File(url.toString() ) ;
+
+		String localPath = Main.pref.get( PreferenceEditor.PREFIX + ".mirror." + url);
+		File oldFile = null;
+		if( localPath != null && localPath.length() > 0)
+		{
+			StringTokenizer st = new StringTokenizer(localPath, ";");
+			long checkDate = Long.parseLong(st.nextToken());
+			localPath = st.nextToken();
+			oldFile = new File(localPath);
+			maxTime = (maxTime <= 0) ? 7 * 24 * 60 * 60 * 1000 : maxTime * 1000;
+			if( System.currentTimeMillis() - checkDate < maxTime )
+			{
+				if( oldFile.exists() )
+					return oldFile;
+			}
+		}
+
+		File destDirFile = new File(destDir);
+		if( !destDirFile.exists() )
+			destDirFile.mkdirs();
+
+		localPath = destDir + System.currentTimeMillis() + "-" + new File(url.getPath()).getName();
+		BufferedOutputStream bos = null;
+		BufferedInputStream bis = null;
+		try
+		{
+			URLConnection conn = url.openConnection();
+			conn.setConnectTimeout(5000);
+			bis = new BufferedInputStream(conn.getInputStream());
+			bos = new BufferedOutputStream( new FileOutputStream(localPath) );
+			byte[] buffer = new byte[4096];
+			int length;
+			while( (length = bis.read( buffer )) > -1 )
+			{
+				bos.write( buffer, 0, length );
+			}
+		}
+		catch(IOException ioe)
+		{
+			if( oldFile != null )
+				return oldFile;
+			else
+				return null;
+		}
+		finally
+		{
+			if( bis != null )
+			{
+				try {
+					bis.close();
+				} catch (IOException e) {
+					e.printStackTrace();
+				}
+			}
+			if( bos != null )
+			{
+				try {
+					bos.close();
+				} catch (IOException e) {
+					e.printStackTrace();
+				}
+			}
+		}
+
+		Main.pref.put( PreferenceEditor.PREFIX + ".mirror." + url, System.currentTimeMillis() + ";" + localPath);
+
+		if( oldFile != null )
+			oldFile.delete();
+
+		return new File(localPath);
+	}
+
+	/**
+	 * Returns the start and end cells of a way.
+	 * @param w The way
+	 * @param cellWays The map with all cells
+	 * @return A list with all the cells the way starts or ends
+	 */
+	public static List<List<Way>> getWaysInCell(Way w, Map<Point2D,List<Way>> cellWays)
+	{
 		if (w.nodes.size() == 0)
-            return Collections.emptyList();
+			return Collections.emptyList();
 
 		Node n1 = w.nodes.get(0);
 		Node n2 = w.nodes.get(w.nodes.size() - 1);
-        
-        List<List<Way>> cells = new ArrayList<List<Way>>(2);
-        Set<Point2D> cellNodes = new HashSet<Point2D>();
-        Point2D cell;
-
-        // First, round coordinates
-        long x0 = Math.round(n1.eastNorth.east()  * 10000);
-        long y0 = Math.round(n1.eastNorth.north() * 10000);
-        long x1 = Math.round(n2.eastNorth.east()  * 10000);
-        long y1 = Math.round(n2.eastNorth.north() * 10000);
-
-        // Start of the way
-        cell = new Point2D.Double(x0, y0);
-        cellNodes.add(cell);
-        List<Way> ways = cellWays.get( cell );
-        if( ways == null )
-        {
-            ways = new ArrayList<Way>();
-            cellWays.put(cell, ways);
-        }
-        cells.add(ways);
-        
-        // End of the way
-        cell = new Point2D.Double(x1, y1);
-        if( !cellNodes.contains(cell) )
-        {
-            cellNodes.add(cell);
-            ways = cellWays.get( cell );
-            if( ways == null )
-            {
-                ways = new ArrayList<Way>();
-                cellWays.put(cell, ways);
-            }
-            cells.add(ways);
-        }
-
-        // Then floor coordinates, in case the way is in the border of the cell.
-        x0 = (long)Math.floor(n1.eastNorth.east()  * 10000);
-        y0 = (long)Math.floor(n1.eastNorth.north() * 10000);
-        x1 = (long)Math.floor(n2.eastNorth.east()  * 10000);
-        y1 = (long)Math.floor(n2.eastNorth.north() * 10000);
-
-        // Start of the way
-        cell = new Point2D.Double(x0, y0);
-        if( !cellNodes.contains(cell) )
-        {
-            cellNodes.add(cell);
-            ways = cellWays.get( cell );
-            if( ways == null )
-            {
-                ways = new ArrayList<Way>();
-                cellWays.put(cell, ways);
-            }
-            cells.add(ways);
-        }
-        
-        // End of the way
-        cell = new Point2D.Double(x1, y1);
-        if( !cellNodes.contains(cell) )
-        {
-            cellNodes.add(cell);
-            ways = cellWays.get( cell );
-            if( ways == null )
-            {
-                ways = new ArrayList<Way>();
-                cellWays.put(cell, ways);
-            }
-            cells.add(ways);
-        }
-
-        return cells;
-    }    
-    
-    /**
+
+		List<List<Way>> cells = new ArrayList<List<Way>>(2);
+		Set<Point2D> cellNodes = new HashSet<Point2D>();
+		Point2D cell;
+
+		// First, round coordinates
+		long x0 = Math.round(n1.eastNorth.east()  * 10000);
+		long y0 = Math.round(n1.eastNorth.north() * 10000);
+		long x1 = Math.round(n2.eastNorth.east()  * 10000);
+		long y1 = Math.round(n2.eastNorth.north() * 10000);
+
+		// Start of the way
+		cell = new Point2D.Double(x0, y0);
+		cellNodes.add(cell);
+		List<Way> ways = cellWays.get( cell );
+		if( ways == null )
+		{
+			ways = new ArrayList<Way>();
+			cellWays.put(cell, ways);
+		}
+		cells.add(ways);
+
+		// End of the way
+		cell = new Point2D.Double(x1, y1);
+		if( !cellNodes.contains(cell) )
+		{
+			cellNodes.add(cell);
+			ways = cellWays.get( cell );
+			if( ways == null )
+			{
+				ways = new ArrayList<Way>();
+				cellWays.put(cell, ways);
+			}
+			cells.add(ways);
+		}
+
+		// Then floor coordinates, in case the way is in the border of the cell.
+		x0 = (long)Math.floor(n1.eastNorth.east()  * 10000);
+		y0 = (long)Math.floor(n1.eastNorth.north() * 10000);
+		x1 = (long)Math.floor(n2.eastNorth.east()  * 10000);
+		y1 = (long)Math.floor(n2.eastNorth.north() * 10000);
+
+		// Start of the way
+		cell = new Point2D.Double(x0, y0);
+		if( !cellNodes.contains(cell) )
+		{
+			cellNodes.add(cell);
+			ways = cellWays.get( cell );
+			if( ways == null )
+			{
+				ways = new ArrayList<Way>();
+				cellWays.put(cell, ways);
+			}
+			cells.add(ways);
+		}
+
+		// End of the way
+		cell = new Point2D.Double(x1, y1);
+		if( !cellNodes.contains(cell) )
+		{
+			cellNodes.add(cell);
+			ways = cellWays.get( cell );
+			if( ways == null )
+			{
+				ways = new ArrayList<Way>();
+				cellWays.put(cell, ways);
+			}
+			cells.add(ways);
+		}
+
+		return cells;
+	}
+
+	/**
 	 * Returns the coordinates of all cells in a grid that a line between 2
 	 * nodes intersects with.
-	 * 
+	 *
 	 * @param n1 The first node.
 	 * @param n2 The second node.
@@ -291,49 +308,49 @@
 	 * @return A list with the coordinates of all cells
 	 */
-	public static List<Point2D> getSegmentCells(Node n1, Node n2, int gridDetail) 
+	public static List<Point2D> getSegmentCells(Node n1, Node n2, int gridDetail)
 	{
 		List<Point2D> cells = new ArrayList<Point2D>();
 		double x0 = n1.eastNorth.east() * gridDetail;
 		double x1 = n2.eastNorth.east() * gridDetail;
-        double y0 = n1.eastNorth.north() * gridDetail + 1;
-        double y1 = n2.eastNorth.north() * gridDetail + 1;
-
-        if( x0 > x1 )
-        {
-        	// Move to 1st-4th cuadrants
-            double aux;
-            aux = x0; x0 = x1; x1 = aux;
-            aux = y0; y0 = y1; y1 = aux;
-        }
-        
-        double dx  = x1 - x0;
-        double dy  = y1 - y0;
-        long stepY = y0 <= y1 ? 1 : -1;
-        long gridX0 = (long)Math.floor(x0);
-        long gridX1 = (long)Math.floor(x1);
-        long gridY0 = (long)Math.floor(y0);
-        long gridY1 = (long)Math.floor(y1);
-        
-        long maxSteps = (gridX1 - gridX0) + Math.abs(gridY1 - gridY0) + 1;
+		double y0 = n1.eastNorth.north() * gridDetail + 1;
+		double y1 = n2.eastNorth.north() * gridDetail + 1;
+
+		if( x0 > x1 )
+		{
+			// Move to 1st-4th cuadrants
+			double aux;
+			aux = x0; x0 = x1; x1 = aux;
+			aux = y0; y0 = y1; y1 = aux;
+		}
+
+		double dx  = x1 - x0;
+		double dy  = y1 - y0;
+		long stepY = y0 <= y1 ? 1 : -1;
+		long gridX0 = (long)Math.floor(x0);
+		long gridX1 = (long)Math.floor(x1);
+		long gridY0 = (long)Math.floor(y0);
+		long gridY1 = (long)Math.floor(y1);
+
+		long maxSteps = (gridX1 - gridX0) + Math.abs(gridY1 - gridY0) + 1;
 		while( (gridX0 <= gridX1 && (gridY0 - gridY1)*stepY <= 0) && maxSteps-- > 0)
-        {
+		{
 			cells.add( new Point2D.Double(gridX0, gridY0) );
-			
-    		// Is the cross between the segment and next vertical line nearer than the cross with next horizontal line? 
-        	// Note: segment line formula: y=dy/dx(x-x1)+y1
-			// Note: if dy < 0, must use *bottom* line. If dy > 0, must use upper line 
-        	double scanY = dy/dx * (gridX0 + 1 - x1) + y1 + (dy < 0 ? -1 : 0);
-        	double scanX = dx/dy * (gridY0 + (dy < 0 ? 0 : 1)*stepY - y1) + x1;
-    		
-        	double distX = Math.pow(gridX0 + 1 - x0, 2) + Math.pow(scanY - y0, 2);
+
+			// Is the cross between the segment and next vertical line nearer than the cross with next horizontal line?
+			// Note: segment line formula: y=dy/dx(x-x1)+y1
+			// Note: if dy < 0, must use *bottom* line. If dy > 0, must use upper line
+			double scanY = dy/dx * (gridX0 + 1 - x1) + y1 + (dy < 0 ? -1 : 0);
+			double scanX = dx/dy * (gridY0 + (dy < 0 ? 0 : 1)*stepY - y1) + x1;
+
+			double distX = Math.pow(gridX0 + 1 - x0, 2) + Math.pow(scanY - y0, 2);
 			double distY = Math.pow(scanX - x0, 2) + Math.pow(gridY0 + stepY - y0, 2);
-			
+
 			if( distX < distY)
-    			gridX0 += 1;
-    		else
-        		gridY0 += stepY;
-        }
-		
+				gridX0 += 1;
+			else
+				gridY0 += stepY;
+		}
+
 		return cells;
-	}   
+	}
 }
