Index: unk/src/org/openstreetmap/josm/actions/ApiPreconditionChecker.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/actions/ApiPreconditionChecker.java	(revision 2167)
+++ 	(revision )
@@ -1,114 +1,0 @@
-package org.openstreetmap.josm.actions;
-
-import static org.openstreetmap.josm.tools.I18n.tr;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Map.Entry;
-
-import javax.swing.JOptionPane;
-
-import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.actions.UploadAction.UploadHook;
-import org.openstreetmap.josm.data.APIDataSet;
-import org.openstreetmap.josm.data.osm.OsmPrimitive;
-import org.openstreetmap.josm.data.osm.Way;
-import org.openstreetmap.josm.gui.ExceptionDialogUtil;
-import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
-import org.openstreetmap.josm.io.OsmApi;
-import org.openstreetmap.josm.io.OsmApiInitializationException;
-
-public class ApiPreconditionChecker implements UploadHook {
-
-    public boolean checkUpload(APIDataSet apiData) {
-        OsmApi api = OsmApi.getOsmApi();
-        try {
-            api.initialize(NullProgressMonitor.INSTANCE);
-            long maxNodes = 0;
-            if (api.getCapabilities().isDefined("waynodes", "maximum")) {
-                maxNodes = api.getCapabilities().getLong("waynodes","maximum");
-            }
-            long maxElements = 0;
-            if (api.getCapabilities().isDefined("changesets", "maximum_elements")) {
-                maxElements = api.getCapabilities().getLong("changesets", "maximum_elements");
-            }
-
-            if (maxNodes > 0) {
-                if( !checkMaxNodes(apiData.getPrimitivesToAdd(), maxNodes))
-                    return false;
-                if( !checkMaxNodes(apiData.getPrimitivesToUpdate(), maxNodes))
-                    return false;
-                if( !checkMaxNodes(apiData.getPrimitivesToDelete(), maxNodes))
-                    return false;
-            }
-
-            if (maxElements  > 0) {
-                int total = 0;
-                total = apiData.getPrimitivesToAdd().size() + apiData.getPrimitivesToUpdate().size() + apiData.getPrimitivesToDelete().size();
-                if(total > maxElements) {
-                    JOptionPane.showMessageDialog(
-                            Main.parent,
-                            tr("Current number of changes exceeds the max. number of changes, current is {0}, max is {1}",
-                                    total,
-                                    maxElements
-                            ),
-                            tr("API Capabilities Violation"),
-                            JOptionPane.ERROR_MESSAGE
-                    );
-                    return false;
-                }
-            }
-        } catch (OsmApiInitializationException e) {
-            ExceptionDialogUtil.explainOsmTransferException(e);
-            return false;
-        }
-        return true;
-    }
-
-    private boolean checkMaxNodes(Collection<OsmPrimitive> primitives, long maxNodes) {
-        for (OsmPrimitive osmPrimitive : primitives) {
-            for (Entry<String,String> e : osmPrimitive.entrySet()) {
-                if(e.getValue().length() > 255) {
-                    if (osmPrimitive.isDeleted()) {
-                        // if OsmPrimitive is going to be deleted we automatically shorten the
-                        // value
-                        System.out.println(
-                                tr("Warning: automatically truncating value of tag ''{0}'' on deleted primitive {1}",
-                                        e.getKey(),
-                                        Long.toString(osmPrimitive.getId())
-                                )
-                        );
-                        osmPrimitive.put(e.getKey(), e.getValue().substring(0, 255));
-                        continue;
-                    }
-                    JOptionPane.showMessageDialog(Main.parent,
-                            tr("Length of value for tag ''{0}'' on primitive {1} exceeds the max. allowed length {2}. Values length is {3}.",
-                                    e.getKey(), Long.toString(osmPrimitive.getId()), 255, e.getValue().length()
-                            ),
-                            tr("Precondition Violation"),
-                            JOptionPane.ERROR_MESSAGE
-                    );
-                    Main.main.getCurrentDataSet().setSelected(Collections.singleton(osmPrimitive));
-                    return false;
-                }
-            }
-
-            if (osmPrimitive instanceof Way &&
-                    ((Way)osmPrimitive).getNodesCount() > maxNodes) {
-                JOptionPane.showMessageDialog(
-                        Main.parent,
-                        tr("{0} nodes in way {1} exceed the max. allowed number of nodes {2}",
-                                ((Way)osmPrimitive).getNodesCount(),
-                                Long.toString(osmPrimitive.getId()),
-                                maxNodes
-                        ),
-                        tr("API Capabilities Violation"),
-                        JOptionPane.ERROR_MESSAGE
-                );
-                Main.main.getCurrentDataSet().setSelected(Collections.singleton(osmPrimitive));
-                return false;
-            }
-        }
-        return true;
-    }
-}
Index: /trunk/src/org/openstreetmap/josm/actions/UploadAction.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/actions/UploadAction.java	(revision 2167)
+++ /trunk/src/org/openstreetmap/josm/actions/UploadAction.java	(revision 2168)
@@ -19,4 +19,8 @@
 
 import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.upload.ApiPreconditionCheckerHook;
+import org.openstreetmap.josm.actions.upload.RelationUploadOrderHook;
+import org.openstreetmap.josm.actions.upload.UploadHook;
+import org.openstreetmap.josm.actions.upload.UploadParameterHook;
 import org.openstreetmap.josm.data.APIDataSet;
 import org.openstreetmap.josm.data.conflict.ConflictCollection;
@@ -67,5 +71,10 @@
          * Checks server capabilities before upload.
          */
-        uploadHooks.add(new ApiPreconditionChecker());
+        uploadHooks.add(new ApiPreconditionCheckerHook());
+
+        /**
+         * Adjusts the upload order of new relations
+         */
+        uploadHooks.add(new RelationUploadOrderHook());
 
         /**
@@ -73,5 +82,5 @@
          * give the user the possibility to cancel the upload.
          */
-        uploadHooks.add(new UploadConfirmationHook());
+        uploadHooks.add(new UploadParameterHook());
     }
 
@@ -99,14 +108,4 @@
         }
     }
-
-    /** Upload Hook */
-    public interface UploadHook {
-        /**
-         * Checks the upload.
-         * @param apiDataSet the data to upload
-         */
-        public boolean checkUpload(APIDataSet apiDataSet);
-    }
-
 
     public UploadAction() {
@@ -483,18 +482,4 @@
     }
 
-
-    static public class UploadConfirmationHook implements UploadHook {
-
-        public boolean checkUpload(APIDataSet apiData) {
-            final UploadDialog dialog = UploadDialog.getUploadDialog();
-            dialog.setUploadedPrimitives(apiData.getPrimitivesToAdd(),apiData.getPrimitivesToUpdate(), apiData.getPrimitivesToDelete());
-            dialog.setVisible(true);
-            if (dialog.isCanceled())
-                return false;
-            dialog.rememberUserInput();
-            return true;
-        }
-    }
-
     public UploadDiffTask createUploadTask(OsmDataLayer layer, Collection<OsmPrimitive> toUpload, Changeset changeset, boolean closeChangesetAfterUpload) {
         return new UploadDiffTask(layer, toUpload, changeset, closeChangesetAfterUpload);
Index: /trunk/src/org/openstreetmap/josm/actions/upload/ApiPreconditionCheckerHook.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/actions/upload/ApiPreconditionCheckerHook.java	(revision 2168)
+++ /trunk/src/org/openstreetmap/josm/actions/upload/ApiPreconditionCheckerHook.java	(revision 2168)
@@ -0,0 +1,113 @@
+package org.openstreetmap.josm.actions.upload;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map.Entry;
+
+import javax.swing.JOptionPane;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.APIDataSet;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.gui.ExceptionDialogUtil;
+import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
+import org.openstreetmap.josm.io.OsmApi;
+import org.openstreetmap.josm.io.OsmApiInitializationException;
+
+public class ApiPreconditionCheckerHook implements UploadHook {
+
+    public boolean checkUpload(APIDataSet apiData) {
+        OsmApi api = OsmApi.getOsmApi();
+        try {
+            api.initialize(NullProgressMonitor.INSTANCE);
+            long maxNodes = 0;
+            if (api.getCapabilities().isDefined("waynodes", "maximum")) {
+                maxNodes = api.getCapabilities().getLong("waynodes","maximum");
+            }
+            long maxElements = 0;
+            if (api.getCapabilities().isDefined("changesets", "maximum_elements")) {
+                maxElements = api.getCapabilities().getLong("changesets", "maximum_elements");
+            }
+
+            if (maxNodes > 0) {
+                if( !checkMaxNodes(apiData.getPrimitivesToAdd(), maxNodes))
+                    return false;
+                if( !checkMaxNodes(apiData.getPrimitivesToUpdate(), maxNodes))
+                    return false;
+                if( !checkMaxNodes(apiData.getPrimitivesToDelete(), maxNodes))
+                    return false;
+            }
+
+            if (maxElements  > 0) {
+                int total = 0;
+                total = apiData.getPrimitivesToAdd().size() + apiData.getPrimitivesToUpdate().size() + apiData.getPrimitivesToDelete().size();
+                if(total > maxElements) {
+                    JOptionPane.showMessageDialog(
+                            Main.parent,
+                            tr("Current number of changes exceeds the max. number of changes, current is {0}, max is {1}",
+                                    total,
+                                    maxElements
+                            ),
+                            tr("API Capabilities Violation"),
+                            JOptionPane.ERROR_MESSAGE
+                    );
+                    return false;
+                }
+            }
+        } catch (OsmApiInitializationException e) {
+            ExceptionDialogUtil.explainOsmTransferException(e);
+            return false;
+        }
+        return true;
+    }
+
+    private boolean checkMaxNodes(Collection<OsmPrimitive> primitives, long maxNodes) {
+        for (OsmPrimitive osmPrimitive : primitives) {
+            for (Entry<String,String> e : osmPrimitive.entrySet()) {
+                if(e.getValue().length() > 255) {
+                    if (osmPrimitive.isDeleted()) {
+                        // if OsmPrimitive is going to be deleted we automatically shorten the
+                        // value
+                        System.out.println(
+                                tr("Warning: automatically truncating value of tag ''{0}'' on deleted primitive {1}",
+                                        e.getKey(),
+                                        Long.toString(osmPrimitive.getId())
+                                )
+                        );
+                        osmPrimitive.put(e.getKey(), e.getValue().substring(0, 255));
+                        continue;
+                    }
+                    JOptionPane.showMessageDialog(Main.parent,
+                            tr("Length of value for tag ''{0}'' on primitive {1} exceeds the max. allowed length {2}. Values length is {3}.",
+                                    e.getKey(), Long.toString(osmPrimitive.getId()), 255, e.getValue().length()
+                            ),
+                            tr("Precondition Violation"),
+                            JOptionPane.ERROR_MESSAGE
+                    );
+                    Main.main.getCurrentDataSet().setSelected(Collections.singleton(osmPrimitive));
+                    return false;
+                }
+            }
+
+            if (osmPrimitive instanceof Way &&
+                    ((Way)osmPrimitive).getNodesCount() > maxNodes) {
+                JOptionPane.showMessageDialog(
+                        Main.parent,
+                        tr("{0} nodes in way {1} exceed the max. allowed number of nodes {2}",
+                                ((Way)osmPrimitive).getNodesCount(),
+                                Long.toString(osmPrimitive.getId()),
+                                maxNodes
+                        ),
+                        tr("API Capabilities Violation"),
+                        JOptionPane.ERROR_MESSAGE
+                );
+                Main.main.getCurrentDataSet().setSelected(Collections.singleton(osmPrimitive));
+                return false;
+            }
+        }
+        return true;
+    }
+}
Index: /trunk/src/org/openstreetmap/josm/actions/upload/CyclicUploadDependencyException.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/actions/upload/CyclicUploadDependencyException.java	(revision 2168)
+++ /trunk/src/org/openstreetmap/josm/actions/upload/CyclicUploadDependencyException.java	(revision 2168)
@@ -0,0 +1,50 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.actions.upload;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Stack;
+
+import org.openstreetmap.josm.data.osm.Relation;
+
+public class CyclicUploadDependencyException extends Exception {
+    private Stack<Relation> cycle;
+
+    public CyclicUploadDependencyException(Stack<Relation> cycle) {
+        super();
+        this.cycle = cycle;
+    }
+
+    protected String formatRelation(Relation r) {
+        StringBuffer sb = new StringBuffer();
+        if (r.getName() != null) {
+            sb.append("'").append(r.getName()).append("'");
+        } else if (r.getId() > 0) {
+            sb.append(r.getId());
+        } else {
+            sb.append("relation@").append(r.hashCode());
+        }
+        return sb.toString();
+    }
+
+    @Override
+    public String getMessage() {
+        StringBuffer sb = new StringBuffer();
+        sb.append(tr("Cyclic dependency between relations:"));
+        sb.append("[");
+        for (int i=0; i< cycle.size(); i++) {
+            if (i >0 ) {
+                sb.append(",");
+            }
+            sb.append(formatRelation(cycle.get(i)));
+        }
+        sb.append("]");
+        return sb.toString();
+    }
+
+    public List<Relation> getCyclicUploadDependency() {
+        return new ArrayList<Relation>(cycle);
+    }
+}
Index: /trunk/src/org/openstreetmap/josm/actions/upload/RelationUploadOrderHook.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/actions/upload/RelationUploadOrderHook.java	(revision 2168)
+++ /trunk/src/org/openstreetmap/josm/actions/upload/RelationUploadOrderHook.java	(revision 2168)
@@ -0,0 +1,109 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.actions.upload;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTable;
+import javax.swing.table.DefaultTableModel;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.APIDataSet;
+import org.openstreetmap.josm.data.osm.Relation;
+import org.openstreetmap.josm.gui.ExtendedDialog;
+import org.openstreetmap.josm.gui.OsmPrimitivRenderer;
+import org.openstreetmap.josm.tools.WindowGeometry;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import org.openstreetmap.josm.actions.upload.UploadHook;
+
+/**
+ * This upload hook reorders the list of new relations to upload such that child
+ * relations are uploaded before parent relations. It also checks for cyclic
+ * dependencies in the list of new relations.
+ * 
+ *
+ */
+public class RelationUploadOrderHook implements UploadHook {
+
+    /** the data to be analysed */
+    private APIDataSet data;
+
+    /**
+     * builds the panel which warns users about a cyclic dependency
+     * 
+     * @param dep  the list of relations with a cyclic dependency
+     * @return the panel
+     */
+    protected JPanel buildWarningPanel(List<Relation> dep) {
+        JPanel pnl = new JPanel();
+        pnl.setLayout(new BorderLayout());
+        String msg = tr("<html>{0} relations build a cycle because they refer to each other.<br>"
+                + "JOSM can''t upload them. Please edit the relations and remove the "
+                + "cyclic dependency.</html>", dep.size()-1);
+        pnl.add(new JLabel(msg), BorderLayout.NORTH);
+
+        DefaultTableModel model = new DefaultTableModel();
+        model.addColumn(tr("Relation ..."));
+        model.addColumn(tr("... refers to relation"));
+        for (int i=0; i<dep.size()-1;i++) {
+            Relation r1 = dep.get(i);
+            Relation r2 = dep.get(i+1);
+            model.addRow(new Relation[] {r1,r2});
+        }
+        JTable tbl = new JTable(model);
+        OsmPrimitivRenderer renderer = new OsmPrimitivRenderer();
+        tbl.getColumnModel().getColumn(0).setCellRenderer(renderer);
+        tbl.getColumnModel().getColumn(1).setCellRenderer(renderer);
+        pnl.add(new JScrollPane(tbl), BorderLayout.CENTER);
+        return pnl;
+    }
+
+    /**
+     * Warns the user if a cyclic dependency is detected
+     * 
+     * @param e the cyclic dependency exception
+     */
+    protected void warnCyclicUploadDependency(CyclicUploadDependencyException e) {
+        List<Relation> dep = e.getCyclicUploadDependency();
+        Relation last = dep.get(dep.size() -1);
+        Iterator<Relation> it = dep.iterator();
+        while(it.hasNext()) {
+            if (it.next() != last) {
+                it.remove();
+            } else {
+                break;
+            }
+        }
+        JPanel pnl = buildWarningPanel(dep);
+        ExtendedDialog dialog = new ExtendedDialog(
+                Main.parent,
+                tr("Cycling dependencies"),
+                new String[] {tr("OK")}
+        );
+        dialog.setContent(pnl, false /* don't embed in scroll pane */);
+        dialog.setButtonIcons(new String[] {"ok"});
+        dialog.setRememberWindowGeometry(
+                getClass().getName() + ".geometry",
+                WindowGeometry.centerInWindow(Main.parent, new Dimension(300, 300))
+        );
+        dialog.showDialog();
+    }
+
+    public boolean checkUpload(APIDataSet apiDataSet) {
+        this.data = apiDataSet;
+        try {
+            data.adjustRelationUploadOrder();
+            return true;
+        } catch(CyclicUploadDependencyException e) {
+            warnCyclicUploadDependency(e);
+            return false;
+        }
+    }
+}
Index: /trunk/src/org/openstreetmap/josm/actions/upload/UploadHook.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/actions/upload/UploadHook.java	(revision 2168)
+++ /trunk/src/org/openstreetmap/josm/actions/upload/UploadHook.java	(revision 2168)
@@ -0,0 +1,12 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.actions.upload;
+
+import org.openstreetmap.josm.data.APIDataSet;
+
+public interface UploadHook {
+    /**
+     * Checks the upload.
+     * @param apiDataSet the data to upload
+     */
+    public boolean checkUpload(APIDataSet apiDataSet);
+}
Index: /trunk/src/org/openstreetmap/josm/actions/upload/UploadParameterHook.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/actions/upload/UploadParameterHook.java	(revision 2168)
+++ /trunk/src/org/openstreetmap/josm/actions/upload/UploadParameterHook.java	(revision 2168)
@@ -0,0 +1,18 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.actions.upload;
+
+import org.openstreetmap.josm.data.APIDataSet;
+import org.openstreetmap.josm.gui.io.UploadDialog;
+
+public class UploadParameterHook implements UploadHook {
+
+    public boolean checkUpload(APIDataSet apiData) {
+        final UploadDialog dialog = UploadDialog.getUploadDialog();
+        dialog.setUploadedPrimitives(apiData.getPrimitivesToAdd(),apiData.getPrimitivesToUpdate(), apiData.getPrimitivesToDelete());
+        dialog.setVisible(true);
+        if (dialog.isCanceled())
+            return false;
+        dialog.rememberUserInput();
+        return true;
+    }
+}
Index: /trunk/src/org/openstreetmap/josm/data/APIDataSet.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/APIDataSet.java	(revision 2167)
+++ /trunk/src/org/openstreetmap/josm/data/APIDataSet.java	(revision 2168)
@@ -2,9 +2,24 @@
 package org.openstreetmap.josm.data;
 
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Set;
+import java.util.Stack;
+import java.util.logging.Logger;
 
 import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.Node;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.Relation;
+import org.openstreetmap.josm.data.osm.RelationMember;
+import org.openstreetmap.josm.data.osm.Way;
+
+import org.openstreetmap.josm.actions.upload.CyclicUploadDependencyException;
 
 /**
@@ -13,5 +28,4 @@
  * The collection is derived from the modified primitives of an {@see DataSet}.
  * 
- * FIXME: use to optimize the upload order before uploading, see various tickets in trac
  * 
  */
@@ -113,3 +127,138 @@
         return ret;
     }
+
+    /**
+     * Adjusts the upload order for new relations. Child relations are uploaded first,
+     * parent relations second.
+     * 
+     * This method detects cyclic dependencies in new relation. Relations with cyclic
+     * dependencies can't be uploaded.
+     * 
+     * @throws CyclicUploadDependencyException thrown, if a cyclic dependency is detected
+     */
+    public void adjustRelationUploadOrder() throws CyclicUploadDependencyException{
+        LinkedList<OsmPrimitive> newToAdd = new LinkedList<OsmPrimitive>();
+        newToAdd.addAll(OsmPrimitive.getFilteredList(toAdd, Node.class));
+        newToAdd.addAll(OsmPrimitive.getFilteredList(toAdd, Way.class));
+
+        List<Relation> relationsToAdd = OsmPrimitive.getFilteredList(toAdd, Relation.class);
+        List<Relation> noProblemRelations = filterRelationsNotReferringToNewRelations(relationsToAdd);
+        newToAdd.addAll(noProblemRelations);
+        relationsToAdd.removeAll(noProblemRelations);
+
+        RelationUploadDependencyGraph graph = new RelationUploadDependencyGraph(relationsToAdd);
+        newToAdd.addAll(graph.computeUploadOrder());
+        toAdd = newToAdd;
+    }
+
+    /**
+     * Replies the subset of relations in <code>relations</code> which are not referring to any
+     * new relation
+     * 
+     * @param relations a list of relations
+     * @return the subset of relations in <code>relations</code> which are not referring to any
+     * new relation
+     */
+    protected List<Relation> filterRelationsNotReferringToNewRelations(Collection<Relation> relations) {
+        List<Relation> ret = new LinkedList<Relation>();
+        for (Relation relation: relations) {
+            boolean refersToNewRelation = false;
+            for (RelationMember m : relation.getMembers()) {
+                if (m.isRelation() && m.getMember().getId() <= 0) {
+                    refersToNewRelation = true;
+                    break;
+                }
+            }
+            if (!refersToNewRelation) {
+                ret.add(relation);
+            }
+        }
+        return ret;
+    }
+
+    /**
+     * Utility class to sort a collection of of new relations with their dependencies
+     * topologically.
+     * 
+     */
+    private class RelationUploadDependencyGraph {
+        private final Logger logger = Logger.getLogger(RelationUploadDependencyGraph.class.getName());
+        private HashMap<Relation, Set<Relation>> children;
+        private Collection<Relation> relations;
+        private Set<Relation> visited;
+        private List<Relation> uploadOrder;
+
+        public RelationUploadDependencyGraph() {
+            this.children = new HashMap<Relation, Set<Relation>>();
+            this.visited = new HashSet<Relation>();
+        }
+
+        public RelationUploadDependencyGraph(Collection<Relation> relations) {
+            this();
+            build(relations);
+        }
+
+        public void build(Collection<Relation> relations) {
+            this.relations = new HashSet<Relation>();
+            for(Relation relation: relations) {
+                if (relation.getId() > 0 ) {
+                    continue;
+                }
+                this.relations.add(relation);
+                for (RelationMember m: relation.getMembers()) {
+                    if (m.isRelation() && m.getMember().getId() == 0) {
+                        addDependency(relation, (Relation)m.getMember());
+                    }
+                }
+            }
+        }
+
+        public Set<Relation> getChildren(Relation relation) {
+            Set<Relation> p = children.get(relation);
+            if (p == null) {
+                p = new HashSet<Relation>();
+                children.put(relation, p);
+            }
+            return p;
+        }
+
+        public void addDependency(Relation relation, Relation child) {
+            getChildren(relation).add(child);
+        }
+
+        protected void visit(Stack<Relation> path, Relation current) throws CyclicUploadDependencyException{
+            if (path.contains(current)) {
+                path.push(current);
+                throw new CyclicUploadDependencyException(path);
+            }
+            if (!visited.contains(current)) {
+                path.push(current);
+                visited.add(current);
+                for (Relation dependent : getChildren(current)) {
+                    visit(path,dependent);
+                }
+                uploadOrder.add(current);
+                path.pop();
+            }
+        }
+
+        public List<Relation> computeUploadOrder() throws CyclicUploadDependencyException {
+            visited = new HashSet<Relation>();
+            uploadOrder = new LinkedList<Relation>();
+            Stack<Relation> path = new Stack<Relation>();
+            for (Relation relation: relations) {
+                visit(path, relation);
+            }
+            ArrayList<Relation> ret = new ArrayList<Relation>(relations);
+            Collections.sort(
+                    ret,
+                    new Comparator<Relation>() {
+                        public int compare(Relation o1, Relation o2) {
+                            return new Integer(uploadOrder.indexOf(o1)).compareTo(uploadOrder.indexOf(o2));
+                        }
+                    }
+            );
+            return ret;
+        }
+    }
 }
Index: /trunk/src/org/openstreetmap/josm/gui/ExtendedDialog.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/ExtendedDialog.java	(revision 2167)
+++ /trunk/src/org/openstreetmap/josm/gui/ExtendedDialog.java	(revision 2168)
@@ -298,5 +298,5 @@
 
         // Ensure all required variables are available
-        if(rememberSizePref.length() == 0 && defaultWindowGeometry != null) {
+        if(rememberSizePref.length() != 0 && defaultWindowGeometry != null) {
             if(visible) {
                 new WindowGeometry(rememberSizePref,
Index: /trunk/test/unit/org/openstreetmap/josm/data/osm/APIDataSetTest.java
===================================================================
--- /trunk/test/unit/org/openstreetmap/josm/data/osm/APIDataSetTest.java	(revision 2168)
+++ /trunk/test/unit/org/openstreetmap/josm/data/osm/APIDataSetTest.java	(revision 2168)
@@ -0,0 +1,182 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.osm;
+
+import java.util.List;
+
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+import org.openstreetmap.josm.actions.upload.CyclicUploadDependencyException;
+import org.openstreetmap.josm.data.APIDataSet;
+
+
+public class APIDataSetTest {
+
+
+    @Test
+    public void oneNewRelationOnly() {
+        Relation r = new Relation();
+        r.put("name", "r1");
+        r.incomplete = false;
+        DataSet ds = new DataSet();
+        ds.relations.add(r);
+
+        APIDataSet apiDataSet = new APIDataSet();
+        apiDataSet.init(ds);
+        try {
+            apiDataSet.adjustRelationUploadOrder();
+        } catch(CyclicUploadDependencyException e) {
+            fail("unexpected exception:" + e);
+        }
+        List<OsmPrimitive> toAdd = apiDataSet.getPrimitivesToAdd();
+
+        assertEquals(1, toAdd.size());
+        assertEquals(r, toAdd.get(0));
+    }
+
+    @Test
+    public void newParentChildPair() {
+        Relation r1 = new Relation();
+        r1.put("name", "r1");
+        r1.incomplete = false;
+
+        Relation r2 = new Relation();
+        r2.put("name", "r2");
+        r2.incomplete = false;
+
+        r1.addMember(new RelationMember("", r2));
+
+        DataSet ds = new DataSet();
+        ds.relations.add(r1);
+        ds.relations.add(r2);
+
+        APIDataSet apiDataSet = new APIDataSet();
+        apiDataSet.init(ds);
+        try {
+            apiDataSet.adjustRelationUploadOrder();
+        } catch(CyclicUploadDependencyException e) {
+            fail("unexpected exception:" + e);
+        }
+        List<OsmPrimitive> toAdd = apiDataSet.getPrimitivesToAdd();
+
+        assertEquals(2, toAdd.size());
+        assertEquals(r2, toAdd.get(0)); // child first
+        assertEquals(r1, toAdd.get(1)); // ... then the parent
+    }
+
+    @Test
+    public void oneExistingAndThreNewInAChain() {
+        Relation r1 = new Relation();
+        r1.put("name", "r1");
+        r1.incomplete = false;
+
+        Relation r2 = new Relation();
+        r2.put("name", "r2");
+        r2.incomplete = false;
+
+        Relation r3 = new Relation();
+        r3.put("name", "r3");
+        r3.incomplete = false;
+
+        Relation r4 = new Relation(1);
+        r4.put("name", "r4");
+        r4.incomplete = false;
+        r4.setModified(true);
+
+        r1.addMember(new RelationMember("", r2));
+        r2.addMember(new RelationMember("", r3));
+
+        DataSet ds = new DataSet();
+        ds.relations.add(r1);
+        ds.relations.add(r2);
+        ds.relations.add(r3);
+        ds.relations.add(r4);
+
+        APIDataSet apiDataSet = new APIDataSet();
+        apiDataSet.init(ds);
+        try {
+            apiDataSet.adjustRelationUploadOrder();
+        } catch(CyclicUploadDependencyException e) {
+            fail("unexpected exception:" + e);
+        }
+        List<OsmPrimitive> toAdd = apiDataSet.getPrimitivesToAdd();
+
+        assertEquals(3, toAdd.size());
+        assertEquals(r3, toAdd.get(0));
+        assertEquals(r2, toAdd.get(1));
+        assertEquals(r1, toAdd.get(2));
+
+        List<OsmPrimitive> toUpdate = apiDataSet.getPrimitivesToUpdate();
+        assertEquals(1, toUpdate.size());
+        assertEquals(r4, toUpdate.get(0));
+    }
+
+    @Test
+    public void oneParentTwoNewChildren() {
+        Relation r1 = new Relation();
+        r1.put("name", "r1");
+        r1.incomplete = false;
+
+        Relation r2 = new Relation();
+        r2.put("name", "r2");
+        r2.incomplete = false;
+
+        Relation r3 = new Relation();
+        r3.put("name", "r3");
+        r3.incomplete = false;
+
+        r1.addMember(new RelationMember("", r2));
+        r1.addMember(new RelationMember("", r3));
+
+        DataSet ds = new DataSet();
+        ds.relations.add(r1);
+        ds.relations.add(r2);
+        ds.relations.add(r3);
+
+        APIDataSet apiDataSet = new APIDataSet();
+        apiDataSet.init(ds);
+        try {
+            apiDataSet.adjustRelationUploadOrder();
+        } catch(CyclicUploadDependencyException e) {
+            fail("unexpected exception:" + e);
+        }
+        List<OsmPrimitive> toAdd = apiDataSet.getPrimitivesToAdd();
+
+        assertEquals(3, toAdd.size());
+        assertEquals(true, toAdd.indexOf(r2) < toAdd.indexOf(r1));
+        assertEquals(true, toAdd.indexOf(r3) < toAdd.indexOf(r1));
+    }
+
+    @Test
+    public void oneCycle() {
+        Relation r1 = new Relation();
+        r1.put("name", "r1");
+        r1.incomplete = false;
+
+        Relation r2 = new Relation();
+        r2.put("name", "r2");
+        r2.incomplete = false;
+
+        Relation r3 = new Relation();
+        r3.put("name", "r3");
+        r3.incomplete = false;
+
+        r1.addMember(new RelationMember("", r2));
+        r2.addMember(new RelationMember("", r3));
+        r3.addMember(new RelationMember("", r1));
+
+        DataSet ds = new DataSet();
+        ds.relations.add(r1);
+        ds.relations.add(r2);
+        ds.relations.add(r3);
+
+        APIDataSet apiDataSet = new APIDataSet();
+        apiDataSet.init(ds);
+        try {
+            apiDataSet.adjustRelationUploadOrder();
+            fail("expected cyclic upload dependency exception not thrown");
+        } catch(CyclicUploadDependencyException e) {
+            System.out.println(e);
+        }
+    }
+}
