Index: applications/editors/josm/plugins/reltoolbox/build.xml
===================================================================
--- applications/editors/josm/plugins/reltoolbox/build.xml	(revision 28692)
+++ applications/editors/josm/plugins/reltoolbox/build.xml	(revision 28693)
@@ -30,5 +30,5 @@
 <project name="reltoolbox" default="dist" basedir=".">
     <!-- enter the SVN commit message -->
-    <property name="commit.message" value="RelToolbox: fix redifinition warnings"/>
+    <property name="commit.message" value="RelToolbox: refactored relation fixing code, added associatedStreet as a fixable relation"/>
     <!-- enter the *lowest* JOSM version this plugin is currently compatible with -->
     <property name="plugin.main.version" value="5018"/>
Index: applications/editors/josm/plugins/reltoolbox/src/relcontext/ChosenRelation.java
===================================================================
--- applications/editors/josm/plugins/reltoolbox/src/relcontext/ChosenRelation.java	(revision 28692)
+++ applications/editors/josm/plugins/reltoolbox/src/relcontext/ChosenRelation.java	(revision 28693)
@@ -118,11 +118,19 @@
         if( opacity < 0.01 )
             return;
-
+        
+        Composite oldComposite = g.getComposite();
         Stroke oldStroke = g.getStroke();
-        Composite oldComposite = g.getComposite();
+        g.setStroke(new BasicStroke(9, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
         g.setColor(Color.yellow);
-        g.setStroke(new BasicStroke(9, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
         g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.3f * opacity));
-        for( OsmPrimitive element : chosenRelation.getMemberPrimitives() ) {
+        
+        drawRelations(g, mv, bbox, chosenRelation);
+        
+        g.setComposite(oldComposite);
+        g.setStroke(oldStroke);
+        
+    }
+    private void drawRelations(Graphics2D g, MapView mv, Bounds bbox, Relation rel) {
+        for( OsmPrimitive element : rel.getMemberPrimitives() ) {
             if( element.getType() == OsmPrimitiveType.NODE ) {
                 Node node = (Node)element;
@@ -142,10 +150,11 @@
                 }
             } else if( element.getType() == OsmPrimitiveType.RELATION ) {
-                // todo: draw all relation members (recursion?)
+            	Color oldColor = g.getColor();
+            	g.setColor(Color.magenta);
+                drawRelations(g, mv, bbox, (Relation)element);
+                g.setColor(oldColor);
             }
             // todo: closedway, multipolygon - ?
         }
-        g.setStroke(oldStroke);
-        g.setComposite(oldComposite);
     }
 
Index: applications/editors/josm/plugins/reltoolbox/src/relcontext/RelContextDialog.java
===================================================================
--- applications/editors/josm/plugins/reltoolbox/src/relcontext/RelContextDialog.java	(revision 28692)
+++ applications/editors/josm/plugins/reltoolbox/src/relcontext/RelContextDialog.java	(revision 28693)
@@ -108,8 +108,9 @@
         roleBox.setVisible(false);
         enterRoleAction = new EnterRoleAction(); // just for the shortcut
+        sortAndFixAction = new SortAndFixAction(chosenRelation);
 
         // [±][X] relation U [AZ][Down][Edit]
         chosenRelationPanel = new JPanel(new GridBagLayout());
-        addRemoveMemberAction = new AddRemoveMemberAction(chosenRelation);
+        addRemoveMemberAction = new AddRemoveMemberAction(chosenRelation, sortAndFixAction);
         chosenRelationPanel.add(new JButton(addRemoveMemberAction), GBC.std());
         chosenRelationPanel.add(sizeButton(new JButton(new ClearChosenRelationAction(chosenRelation)), 32, 0), GBC.std());
@@ -118,5 +119,4 @@
         chosenRelationPanel.add(chosenRelationComponent, GBC.std().fill().insets(5, 0, 5, 0));
         chosenRelationPanel.add(roleBox, GBC.std().fill().insets(5, 0, 5, 0));
-        sortAndFixAction = new SortAndFixAction(chosenRelation);
         final JButton sortAndFixButton = (JButton) sizeButton(new JButton(sortAndFixAction), 32, 0);
         chosenRelationPanel.add(sortAndFixButton, GBC.std().fill(GBC.VERTICAL));
Index: applications/editors/josm/plugins/reltoolbox/src/relcontext/actions/AddRemoveMemberAction.java
===================================================================
--- applications/editors/josm/plugins/reltoolbox/src/relcontext/actions/AddRemoveMemberAction.java	(revision 28692)
+++ applications/editors/josm/plugins/reltoolbox/src/relcontext/actions/AddRemoveMemberAction.java	(revision 28693)
@@ -1,9 +1,11 @@
 package relcontext.actions;
 
-import java.util.*;
-import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import static org.openstreetmap.josm.tools.I18n.tr;
+
 import java.awt.event.ActionEvent;
 import java.awt.event.KeyEvent;
+import java.util.ArrayList;
+import java.util.Collection;
+
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.actions.JosmAction;
@@ -11,4 +13,5 @@
 import org.openstreetmap.josm.command.Command;
 import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
 import org.openstreetmap.josm.data.osm.Relation;
@@ -17,4 +20,5 @@
 import org.openstreetmap.josm.tools.ImageProvider;
 import org.openstreetmap.josm.tools.Shortcut;
+
 import relcontext.ChosenRelation;
 import relcontext.ChosenRelationListener;
@@ -30,10 +34,12 @@
     private static final String ACTION_NAME = "Add/remove member";
     private ChosenRelation rel;
+    private SortAndFixAction sortAndFix;
 
-    public AddRemoveMemberAction( ChosenRelation rel ) {
+    public AddRemoveMemberAction( ChosenRelation rel, SortAndFixAction sortAndFix ) {
         super(null, "relcontext/addremove", tr("Add/remove members from the chosen relation"),
                 Shortcut.registerShortcut("reltoolbox:addremove", tr("Relation Toolbox: {0}", tr("Add/remove members from the chosen relation")),
                 KeyEvent.VK_EQUALS, Shortcut.DIRECT), false);
         this.rel = rel;
+        this.sortAndFix = sortAndFix;
         rel.addChosenRelationListener(this);
         updateEnabledState();
@@ -51,5 +57,5 @@
 
         // 0. check if relation is broken (temporary)
-        boolean isBroken = !toAdd.isEmpty() && SortAndFixAction.needsFixing(r);
+        boolean isBroken = !toAdd.isEmpty() && sortAndFix.needsFixing(r);
 
         // 1. remove all present members
@@ -66,5 +72,5 @@
 
         // 3. check for roles again (temporary)
-        Command roleFix = !isBroken && SortAndFixAction.needsFixing(r) ? SortAndFixAction.fixRelation(r) : null;
+        Command roleFix = !isBroken && sortAndFix.needsFixing(r) ? sortAndFix.fixRelation(r) : null;
         if( roleFix != null )
             roleFix.executeCommand();
Index: applications/editors/josm/plugins/reltoolbox/src/relcontext/actions/SortAndFixAction.java
===================================================================
--- applications/editors/josm/plugins/reltoolbox/src/relcontext/actions/SortAndFixAction.java	(revision 28692)
+++ applications/editors/josm/plugins/reltoolbox/src/relcontext/actions/SortAndFixAction.java	(revision 28693)
@@ -1,19 +1,31 @@
 package relcontext.actions;
 
+import static org.openstreetmap.josm.tools.I18n.tr;
+
 import java.awt.event.ActionEvent;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.List;
+
 import javax.swing.AbstractAction;
 import javax.swing.Action;
-import static org.openstreetmap.josm.tools.I18n.tr;
+
 import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.command.ChangeCommand;
 import org.openstreetmap.josm.command.Command;
-import org.openstreetmap.josm.data.osm.*;
+import org.openstreetmap.josm.data.osm.Relation;
+import org.openstreetmap.josm.data.osm.RelationMember;
 import org.openstreetmap.josm.tools.ImageProvider;
+
 import relcontext.ChosenRelation;
 import relcontext.ChosenRelationListener;
+import relcontext.relationfix.AssociatedStreetFixer;
+import relcontext.relationfix.BoundaryFixer;
+import relcontext.relationfix.MultipolygonFixer;
+import relcontext.relationfix.NothingFixer;
+import relcontext.relationfix.RelationFixer;
 
 public class SortAndFixAction extends AbstractAction implements ChosenRelationListener {
-    private ChosenRelation rel;
+	private static final long serialVersionUID = 1L;
+	private ChosenRelation rel;
+    private List<RelationFixer> fixers;
 
     public SortAndFixAction( ChosenRelation rel ) {
@@ -25,4 +37,11 @@
         rel.addChosenRelationListener(this);
         setEnabled(false);
+        
+        // construct all available fixers
+        fixers = new ArrayList<RelationFixer>();
+        fixers.add(new BoundaryFixer()); // should be before multipolygon as takes special case of multipolygon relation - boundary
+        fixers.add(new MultipolygonFixer());
+        fixers.add(new AssociatedStreetFixer());
+        
     }
 
@@ -37,26 +56,17 @@
     }
 
-    public static boolean needsFixing( Relation rel ) {
-        return !isIncomplete(rel) && (areMultipolygonTagsEmpty(rel) || areBoundaryTagsNotRight(rel));
+    public boolean needsFixing( Relation rel ) {
+        return !isIncomplete(rel) && !getFixer(rel).isRelationGood(rel);
+    }
+    
+    private RelationFixer getFixer( Relation rel ) {
+    	for(RelationFixer fixer : fixers)
+    		if (fixer.isFixerApplicable(rel))
+    			return fixer;
+    	return new NothingFixer();
     }
 
-    public static Command fixRelation( Relation rel ) {
-        Relation r = rel;
-        boolean fixed = false;
-        // todo: sort members
-        // todo: set roles for multipolygon members
-        Relation rr = fixMultipolygonRoles(r);
-        if( rr != null ) {
-            r = rr;
-            fixed = true;
-        }
-        // todo: set roles for boundary members
-        rr= fixBoundaryRoles(r);
-        if( rr != null ) {
-            r = rr;
-            fixed = true;
-        }
-
-        return fixed ? new ChangeCommand(rel, r) : null;
+    public Command fixRelation( Relation rel ) {
+        return getFixer(rel).fixRelation(rel);
     }
 
@@ -70,95 +80,3 @@
     }
 
-    /**
-     * Check for ways that have roles different from "outer" and "inner".
-     */
-    private static boolean areMultipolygonTagsEmpty( Relation r ) {
-        if( r == null || r.getMembersCount() == 0 || !ChosenRelation.isMultipolygon(r) )
-            return false;
-        for( RelationMember m : r.getMembers() ) {
-            if( m.getType().equals(OsmPrimitiveType.WAY) && (m.getRole() == null || (!m.getRole().equals("outer") && !m.getRole().equals("inner"))) )
-                return true;
-        }
-        return false;
-    }
-
-    /**
-     * Check for nodes and relations without needed roles.
-     */
-    private static boolean areBoundaryTagsNotRight( Relation r ) {
-        if( r == null || r.getMembersCount() == 0 || !r.hasKey("type") || !r.get("type").equals("boundary") )
-            return false;
-        for( RelationMember m : r.getMembers() ) {
-            if( m.getType().equals(OsmPrimitiveType.RELATION) && (m.getRole() == null || !m.getRole().equals("subarea")) )
-                return true;
-            else if(m.getType().equals(OsmPrimitiveType.NODE) && (m.getRole() == null || (!m.getRole().equals("label") && !m.getRole().equals("admin_centre"))) )
-                return true;
-        }
-        return false;
-    }
-
-    /**
-     * Basically, created multipolygon from scratch, and if successful, replace roles with new ones.
-     */
-    private static Relation fixMultipolygonRoles( Relation source ) {
-        Collection<Way> ways = new ArrayList<Way>();
-        for( OsmPrimitive p : source.getMemberPrimitives() )
-            if( p instanceof Way )
-                ways.add((Way)p);
-        MultipolygonCreate mpc = new MultipolygonCreate();
-        String error = mpc.makeFromWays(ways);
-        if( error != null )
-            return null;
-
-        Relation r = new Relation(source);
-        boolean fixed = false;
-        Set<Way> outerWays = new HashSet<Way>();
-        for( MultipolygonCreate.JoinedPolygon poly : mpc.outerWays )
-            for( Way w : poly.ways )
-                outerWays.add(w);
-        Set<Way> innerWays = new HashSet<Way>();
-        for( MultipolygonCreate.JoinedPolygon poly : mpc.innerWays )
-            for( Way w : poly.ways )
-                innerWays.add(w);
-        for( int i = 0; i < r.getMembersCount(); i++ ) {
-            RelationMember m = r.getMember(i);
-            if( m.isWay() ) {
-                String role = null;
-                if( outerWays.contains((Way)m.getMember()) )
-                    role = "outer";
-                else if( innerWays.contains((Way)m.getMember()) )
-                    role = "inner";
-                if( role != null && !role.equals(m.getRole()) ) {
-                    r.setMember(i, new RelationMember(role, m.getMember()));
-                    fixed = true;
-                }
-            }
-        }
-        return fixed ? r : null;
-    }
-
-    private static Relation fixBoundaryRoles( Relation source ) {
-        Relation r = new Relation(source);
-        boolean fixed = false;
-        for( int i = 0; i < r.getMembersCount(); i++ ) {
-            RelationMember m = r.getMember(i);
-            String role = null;
-            if( m.isRelation() )
-                role = "subarea";
-            else if( m.isNode() ) {
-                Node n = (Node)m.getMember();
-                if( !n.isIncomplete() ) {
-                    if( n.hasKey("place") )
-                        role = "admin_centre";
-                    else
-                        role = "label";
-                }
-            }
-            if( role != null && !role.equals(m.getRole()) ) {
-                r.setMember(i, new RelationMember(role, m.getMember()));
-                fixed = true;
-            }
-        }
-        return fixed ? r : null;
-    }
 }
Index: applications/editors/josm/plugins/reltoolbox/src/relcontext/relationfix/AssociatedStreetFixer.java
===================================================================
--- applications/editors/josm/plugins/reltoolbox/src/relcontext/relationfix/AssociatedStreetFixer.java	(revision 28693)
+++ applications/editors/josm/plugins/reltoolbox/src/relcontext/relationfix/AssociatedStreetFixer.java	(revision 28693)
@@ -0,0 +1,142 @@
+package relcontext.relationfix;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.openstreetmap.josm.command.ChangeCommand;
+import org.openstreetmap.josm.command.Command;
+import org.openstreetmap.josm.command.SequenceCommand;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
+import org.openstreetmap.josm.data.osm.Relation;
+import org.openstreetmap.josm.data.osm.RelationMember;
+import org.openstreetmap.josm.data.osm.Way;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+public class AssociatedStreetFixer extends RelationFixer {
+
+	public AssociatedStreetFixer() {
+		super("associatedStreet");
+	}
+
+	@Override
+	public boolean isRelationGood(Relation rel) {
+		for (RelationMember m : rel.getMembers()) {
+    		if (m.getType().equals(OsmPrimitiveType.NODE) && !"house".equals(m.getRole()))
+    			return false;
+    		if (m.getType().equals(OsmPrimitiveType.WAY) && !("house".equals(m.getRole()) || "street".equals(m.getRole())))
+    			return false;
+    		if (m.getType().equals(OsmPrimitiveType.RELATION) && !"house".equals(m.getRole()))
+    			return false;
+    	}
+		// relation should have name
+		if (!rel.hasKey("name")) {
+			return false;
+		}
+		// check that all street members have same name as relation (???)
+		String streetName = rel.get("name");
+		for (RelationMember m : rel.getMembers()) {
+			if (m.getRole().equals("street") && !m.getWay().get("name").equals(streetName))
+				return false;
+		}
+		return true;
+	}
+
+	@Override
+	public Command fixRelation(Relation source) {
+		// any way with highway tag -> street
+		// any way/point/relation with addr:housenumber=* or building=* or type=multipolygon -> house
+		// name - check which name is most used in street members and add to relation
+		// copy this name to the other street members (???)
+		Relation rel = new Relation(source);
+		boolean fixed = false;
+		
+		for (int i = 0; i < rel.getMembersCount(); i++) {
+			RelationMember m = rel.getMember(i);
+			
+			if (m.isNode()) {
+				Node node = m.getNode();
+				if (!"house".equals(m.getRole()) && 
+						(node.hasKey("building") || node.hasKey("addr:housenumber"))) {
+					fixed = true;
+					rel.setMember(i, new RelationMember("house", node));
+				}
+			} else if (m.isWay()) {
+				Way way = m.getWay();
+				if (!"street".equals(m.getRole()) && way.hasKey("highway")) {
+					fixed = true;
+					rel.setMember(i, new RelationMember("street", way));
+				} else if (!"house".equals(m.getRole()) && 
+						(way.hasKey("building") || way.hasKey("addr:housenumber"))) {
+					fixed = true;
+					rel.setMember(i,  new RelationMember("house", way));
+				}
+			} else if (m.isRelation()) {
+				Relation relation = m.getRelation();
+				if (!"house".equals(m.getRole()) && 
+						(relation.hasKey("building") || relation.hasKey("addr:housenumber") || "multipolygon".equals(relation.get("type")))) {
+					fixed = true;
+					rel.setMember(i, new RelationMember("house", relation));
+				}
+			}
+		}
+		
+		// fill relation name
+		Map<String, Integer> streetNames = new HashMap<String, Integer>();
+		for (RelationMember m : rel.getMembers()) 
+			if ("street".equals(m.getRole()) && m.isWay()) {
+				String name = m.getWay().get("name");
+				if (name == null || name.isEmpty()) continue;
+				
+				Integer count = streetNames.get(name);
+				
+				streetNames.put(name, count != null? count + 1 : 1);
+			}
+		String commonName = "";
+		Integer commonCount = 0;
+		for (Map.Entry<String, Integer> entry : streetNames.entrySet()) {
+			if (entry.getValue() > commonCount) {
+				commonCount = entry.getValue();
+				commonName = entry.getKey();
+			}
+		}
+		
+		if (!rel.hasKey("name")) {
+			fixed = true;
+			rel.put("name", commonName);
+		} else {
+			commonName = ""; // set empty common name - if we already have name on relation, do not overwrite it
+		}
+		
+		List<Command> commandList = new ArrayList<Command>();
+		if (fixed) {
+			commandList.add(new ChangeCommand(source, rel));
+		}
+		
+		/*if (!commonName.isEmpty())
+		// fill common name to streets
+		for (RelationMember m : rel.getMembers()) 
+			if ("street".equals(m.getRole()) && m.isWay()) {
+				String name = m.getWay().get("name");
+				if (commonName.equals(name)) continue;
+				
+				// TODO: ask user if he really wants to overwrite street name??
+				
+				Way oldWay = m.getWay();
+				Way newWay = new Way(oldWay);
+				newWay.put("name", commonName);
+				
+				commandList.add(new ChangeCommand(oldWay, newWay));
+			}
+		*/
+		// return results
+		if (commandList.size() == 0)
+			return null;
+		if (commandList.size() == 1)
+			return commandList.get(0);
+		return new SequenceCommand(tr("fix associatedStreet relation"), commandList);
+	}
+}
Index: applications/editors/josm/plugins/reltoolbox/src/relcontext/relationfix/BoundaryFixer.java
===================================================================
--- applications/editors/josm/plugins/reltoolbox/src/relcontext/relationfix/BoundaryFixer.java	(revision 28693)
+++ applications/editors/josm/plugins/reltoolbox/src/relcontext/relationfix/BoundaryFixer.java	(revision 28693)
@@ -0,0 +1,84 @@
+package relcontext.relationfix;
+
+import org.openstreetmap.josm.command.ChangeCommand;
+import org.openstreetmap.josm.command.Command;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
+import org.openstreetmap.josm.data.osm.Relation;
+import org.openstreetmap.josm.data.osm.RelationMember;
+
+
+/**
+ * @see http://wiki.openstreetmap.org/wiki/Relation:boundary
+ */
+public class BoundaryFixer extends MultipolygonFixer {
+
+	public BoundaryFixer() {
+		super(new String[]{"boundary", "multipolygon"});
+	}
+	
+	/**
+	 * For boundary relations both "boundary" and "multipolygon" types are applicable, but 
+	 * it should also have key boundary=administrative to be fully boundary.
+	 * @see http://wiki.openstreetmap.org/wiki/Relation:boundary
+	 */
+	@Override
+	public boolean isFixerApplicable(Relation rel) {
+		return super.isFixerApplicable(rel) && "administrative".equals(rel.get("boundary"));
+	}
+	
+	@Override
+	public boolean isRelationGood(Relation rel) {
+		for( RelationMember m : rel.getMembers() ) {
+            if (m.getType().equals(OsmPrimitiveType.RELATION) && !"subarea".equals(m.getRole()))
+                return false;
+            if (m.getType().equals(OsmPrimitiveType.NODE) && !("label".equals(m.getRole()) || "admin_centre".equals(m.getRole())))
+                return false;
+            if (m.getType().equals(OsmPrimitiveType.WAY) && !("outer".equals(m.getRole()) || "inner".equals(m.getRole())))
+				return false;
+        }
+		return true;
+	}
+
+	@Override
+	public Command fixRelation(Relation rel) {
+		Relation r = rel;
+		Relation rr = fixMultipolygonRoles(r);
+		boolean fixed = false;
+		if (rr != null) {
+			fixed = true;
+			r = rr;
+		}
+		rr = fixBoundaryRoles(r);
+		if (rr != null) {
+			fixed = true;
+			r = rr;
+		}
+		return fixed ? new ChangeCommand(rel, r) : null;
+	}
+
+	private Relation fixBoundaryRoles( Relation source ) {
+        Relation r = new Relation(source);
+        boolean fixed = false;
+        for( int i = 0; i < r.getMembersCount(); i++ ) {
+            RelationMember m = r.getMember(i);
+            String role = null;
+            if( m.isRelation() )
+                role = "subarea";
+            else if( m.isNode() ) {
+                Node n = (Node)m.getMember();
+                if( !n.isIncomplete() ) {
+                    if( n.hasKey("place") )
+                        role = "admin_centre";
+                    else
+                        role = "label";
+                }
+            }
+            if( role != null && !role.equals(m.getRole()) ) {
+                r.setMember(i, new RelationMember(role, m.getMember()));
+                fixed = true;
+            }
+        }
+        return fixed ? r : null;
+    }
+}
Index: applications/editors/josm/plugins/reltoolbox/src/relcontext/relationfix/MultipolygonFixer.java
===================================================================
--- applications/editors/josm/plugins/reltoolbox/src/relcontext/relationfix/MultipolygonFixer.java	(revision 28693)
+++ applications/editors/josm/plugins/reltoolbox/src/relcontext/relationfix/MultipolygonFixer.java	(revision 28693)
@@ -0,0 +1,84 @@
+package relcontext.relationfix;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.openstreetmap.josm.command.ChangeCommand;
+import org.openstreetmap.josm.command.Command;
+import org.openstreetmap.josm.data.osm.MultipolygonCreate;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
+import org.openstreetmap.josm.data.osm.Relation;
+import org.openstreetmap.josm.data.osm.RelationMember;
+import org.openstreetmap.josm.data.osm.Way;
+
+/**
+ * @see http://wiki.openstreetmap.org/wiki/Relation:multipolygon
+ */
+public class MultipolygonFixer extends RelationFixer {
+
+	public MultipolygonFixer() {
+		super("multipolygon");
+	}
+	
+	protected MultipolygonFixer(String[] types) {
+		super(types);
+	}
+
+
+	@Override
+	public boolean isRelationGood(Relation rel) {
+		for (RelationMember m : rel.getMembers())
+			if (m.getType().equals(OsmPrimitiveType.WAY) && !("outer".equals(m.getRole()) || "inner".equals(m.getRole())))
+				return false;
+		return true;
+	}
+
+	@Override
+	public Command fixRelation(Relation rel) {
+		Relation rr = fixMultipolygonRoles(rel);
+		return rr != null? new ChangeCommand(rel, rr) : null;
+	}
+
+	/**
+     * Basically, created multipolygon from scratch, and if successful, replace roles with new ones.
+     */
+    protected Relation fixMultipolygonRoles( Relation source ) {
+        Collection<Way> ways = new ArrayList<Way>();
+        for( OsmPrimitive p : source.getMemberPrimitives() )
+            if( p instanceof Way )
+                ways.add((Way)p);
+        MultipolygonCreate mpc = new MultipolygonCreate();
+        String error = mpc.makeFromWays(ways);
+        if( error != null )
+            return null;
+
+        Relation r = new Relation(source);
+        boolean fixed = false;
+        Set<Way> outerWays = new HashSet<Way>();
+        for( MultipolygonCreate.JoinedPolygon poly : mpc.outerWays )
+            for( Way w : poly.ways )
+                outerWays.add(w);
+        Set<Way> innerWays = new HashSet<Way>();
+        for( MultipolygonCreate.JoinedPolygon poly : mpc.innerWays )
+            for( Way w : poly.ways )
+                innerWays.add(w);
+        for( int i = 0; i < r.getMembersCount(); i++ ) {
+            RelationMember m = r.getMember(i);
+            if( m.isWay() ) {
+                String role = null;
+                if( outerWays.contains((Way)m.getMember()) )
+                    role = "outer";
+                else if( innerWays.contains((Way)m.getMember()) )
+                    role = "inner";
+                if( role != null && !role.equals(m.getRole()) ) {
+                    r.setMember(i, new RelationMember(role, m.getMember()));
+                    fixed = true;
+                }
+            }
+        }
+        return fixed ? r : null;
+    }
+}
Index: applications/editors/josm/plugins/reltoolbox/src/relcontext/relationfix/NothingFixer.java
===================================================================
--- applications/editors/josm/plugins/reltoolbox/src/relcontext/relationfix/NothingFixer.java	(revision 28693)
+++ applications/editors/josm/plugins/reltoolbox/src/relcontext/relationfix/NothingFixer.java	(revision 28693)
@@ -0,0 +1,28 @@
+package relcontext.relationfix;
+
+import org.openstreetmap.josm.command.Command;
+import org.openstreetmap.josm.data.osm.Relation;
+
+/**
+ * Default fixer that does nothing - every relation is OK for this class.
+ */
+public class NothingFixer extends RelationFixer {
+
+	public NothingFixer() {
+		super("");
+	}
+	@Override
+	public boolean isFixerApplicable(Relation rel) {
+		return true;
+	}
+	@Override
+	public boolean isRelationGood(Relation rel) {
+		return true;
+	}
+
+	@Override
+	public Command fixRelation(Relation rel) {
+		return null;
+	}
+
+}
Index: applications/editors/josm/plugins/reltoolbox/src/relcontext/relationfix/RelationFixer.java
===================================================================
--- applications/editors/josm/plugins/reltoolbox/src/relcontext/relationfix/RelationFixer.java	(revision 28693)
+++ applications/editors/josm/plugins/reltoolbox/src/relcontext/relationfix/RelationFixer.java	(revision 28693)
@@ -0,0 +1,74 @@
+package relcontext.relationfix;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.openstreetmap.josm.command.Command;
+import org.openstreetmap.josm.data.osm.Relation;
+
+public abstract class RelationFixer {
+	
+	private List<String> applicableTypes;
+	
+	{
+		applicableTypes = new ArrayList<String>();
+	}
+	/**
+	 * Construct new RelationFixer by only one applicable relation type 
+	 * @param type
+	 */
+	public RelationFixer(String type) {
+		applicableTypes.add(type);
+	}
+	
+	/**
+	 * Construct new RelationFixer by an array of applicable types 
+	 * @param types
+	 */
+	public RelationFixer(String[] types) {
+		for(String type: types) {
+			applicableTypes.add(type);
+		}
+	}
+	
+	/**
+	 * Check if given relation is of needed type. You may override this method to check first type
+	 * and then check desired relation properties.
+	 * Note that this only verifies if current RelationFixer can be used to check and fix given relation
+	 * Deeper relation checking is at {@link isRelationGood}  
+	 * 
+	 * @param rel Relation to check
+	 * @return true if relation can be verified by current RelationFixer
+	 */
+	public boolean isFixerApplicable(Relation rel) {
+		if (rel == null)
+			return false;
+		if (!rel.hasKey("type"))
+			return false;
+		
+		String type = rel.get("type");
+		for(String oktype: applicableTypes)
+			if (oktype.equals(type)) 
+				return true;
+		
+		return false;
+	}
+	
+	/**
+	 * Check if given relation is OK. That means if all roles are given properly, all tags exist as expected etc.
+	 * Should be written in children classes.
+	 * 
+	 * @param rel Relation to verify
+	 * @return true if given relation is OK
+	 */
+	public abstract boolean isRelationGood(Relation rel);
+	
+	/**
+	 * Fix relation and return new relation with fixed tags, roles etc.
+	 * Note that is not obligatory to return true for isRelationGood for new relation
+	 * 
+	 * @param rel Relation to fix
+	 * @return command that fixes the relation {@code null} if it cannot be fixed or is already OK
+	 */
+	public abstract Command fixRelation(Relation rel);
+}
