Index: trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTableLinkedCellRenderer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTableLinkedCellRenderer.java	(revision 3787)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTableLinkedCellRenderer.java	(revision 3788)
@@ -2,7 +2,9 @@
 package org.openstreetmap.josm.gui.dialogs.relation;
 
+import java.awt.BasicStroke;
 import java.awt.Color;
 import java.awt.Component;
 import java.awt.Graphics;
+import java.awt.Graphics2D;
 import java.awt.Image;
 
@@ -40,5 +42,9 @@
 
         int ymax=this.getSize().height - 1;
-        int xloop = 8;
+        int xloop = 10;
+        int xowloop = 0;
+        if(value.isOnewayLoopForwardPart) xowloop = -3;
+        if(value.isOnewayLoopBackwardPart) xowloop = 3;
+        
         int xoff = this.getSize().width / 2;
         if (value.isLoop) {
@@ -52,5 +58,8 @@
         if (value.linkPrev) {
             g.setColor(Color.black);
-            g.fillRect(xoff - 1, 0, 3, 1);
+            if(value.isOnewayHead)
+                g.fillRect(xoff - 1, 0, 3, 1);
+            else
+                g.fillRect(xoff - 1 + xowloop, 0, 3, 1);
             y1 = 0;
         } else {
@@ -64,5 +73,8 @@
             else {
                 g.setColor(Color.red);
-                g.drawRect(xoff-1, p - 1 - w, w, w);
+                if(value.isOnewayHead)
+                    g.drawRect(xoff-1, p - 3 - w, w, w);
+                else
+                    g.drawRect(xoff-1 + xowloop, p - 1 - w, w, w);
                 y1 = p;
             }
@@ -71,5 +83,8 @@
         if (value.linkNext) {
             g.setColor(Color.black);
-            g.fillRect(xoff - 1, ymax, 3, 1);
+            if(value.isOnewayTail)
+                g.fillRect(xoff - 1, ymax, 3, 1);
+            else
+                g.fillRect(xoff - 1 + xowloop, ymax, 3, 1);
             y2 = ymax;
         } else {
@@ -84,5 +99,8 @@
             else {
                 g.setColor(Color.red);
-                g.drawRect(xoff-1, ymax - p + 1, w, w);
+                if(value.isOnewayTail)
+                    g.drawRect(xoff-1, ymax - p + 3, w, w);
+                else
+                    g.drawRect(xoff-1 + xowloop, ymax - p + 1, w, w);
                 y2 = ymax - p;
             }
@@ -91,9 +109,42 @@
         /* vertical lines */
         g.setColor(Color.black);
-        g.drawLine(xoff, y1, xoff, y2);
         if (value.isLoop) {
             g.drawLine(xoff+xloop, y1, xoff+xloop, y2);
         }
 
+        if (value.isOnewayHead) {
+            setDotted(g);
+            y1 = 7;
+
+            int xValues [] = {xoff - xowloop + 1, xoff - xowloop + 1, xoff};
+            int yValues [] = {ymax, y1+1, 1};
+            g.drawPolyline(xValues, yValues, 3);
+            unsetDotted(g);
+            g.drawLine(xoff + xowloop, y1+1, xoff, 1);
+        }
+
+        if(value.isOnewayTail){
+            setDotted(g);
+            y2 = ymax - 7;
+
+            int xValues [] = {xoff+1, xoff - xowloop + 1, xoff - xowloop + 1};
+            int yValues [] = {ymax-1, y2, y1};
+            g.drawPolyline(xValues, yValues, 3);
+            unsetDotted(g);
+            g.drawLine(xoff + xowloop, y2, xoff, ymax-1);
+        }
+
+        if ((value.isOnewayLoopForwardPart || value.isOnewayLoopBackwardPart) && !value.isOnewayTail && !value.isOnewayHead) {
+            setDotted(g);
+            g.drawLine(xoff - xowloop+1, y1, xoff - xowloop+1, y2 + 1);
+            unsetDotted(g);
+        }
+
+        if (!value.isOnewayLoopForwardPart && !value.isOnewayLoopBackwardPart){
+            g.drawLine(xoff, y1, xoff, y2);
+        }
+        
+        g.drawLine(xoff+xowloop, y1, xoff+xowloop, y2);
+      
         /* special icons */
         Image arrow = null;
@@ -106,12 +157,39 @@
             break;
         }
-        if ((arrow != null) && (value.linkPrev || value.linkNext)) {
-            g.drawImage(arrow, xoff-3, (y1 + y2) / 2 - 2, null);
-        }
-        else if (value.direction == Direction.ROUNDABOUT_LEFT) {
+        if (value.direction == Direction.ROUNDABOUT_LEFT) {
             g.drawImage(roundabout_left, xoff-6, 1, null);
         } else if (value.direction == Direction.ROUNDABOUT_RIGHT) {
             g.drawImage(roundabout_right, xoff-6, 1, null);
         }
+
+        if (!value.isOnewayLoopForwardPart && !value.isOnewayLoopBackwardPart &&
+                (arrow != null)) {
+            g.drawImage(arrow, xoff-3, (y1 + y2) / 2 - 2, null);
+        }
+
+        if (value.isOnewayLoopBackwardPart && value.isOnewayLoopForwardPart) {
+            if(arrow == arrowDown)
+                arrow = arrowUp;
+            else if (arrow == arrowUp)
+                arrow = arrowDown;
+        }
+
+        if ((arrow != null)) {
+            g.drawImage(arrow, xoff+xowloop-3, (y1 + y2) / 2 - 2, null);
+        }
+    }
+
+    private void setDotted(Graphics g) {
+        ((Graphics2D)g).setStroke(new BasicStroke(
+              1f,
+              BasicStroke.CAP_BUTT,
+              BasicStroke.CAP_BUTT,
+              5f,
+              new float[] {1f, 2f},
+              0f));
+    }
+
+    private void unsetDotted(Graphics g) {
+        ((Graphics2D)g).setStroke(new BasicStroke());
     }
 }
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTableModel.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTableModel.java	(revision 3787)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTableModel.java	(revision 3788)
@@ -2,9 +2,5 @@
 package org.openstreetmap.josm.gui.dialogs.relation;
 
-import static org.openstreetmap.josm.gui.dialogs.relation.WayConnectionType.Direction.BACKWARD;
-import static org.openstreetmap.josm.gui.dialogs.relation.WayConnectionType.Direction.FORWARD;
-import static org.openstreetmap.josm.gui.dialogs.relation.WayConnectionType.Direction.NONE;
-import static org.openstreetmap.josm.gui.dialogs.relation.WayConnectionType.Direction.ROUNDABOUT_LEFT;
-import static org.openstreetmap.josm.gui.dialogs.relation.WayConnectionType.Direction.ROUNDABOUT_RIGHT;
+import static org.openstreetmap.josm.gui.dialogs.relation.WayConnectionType.Direction.*;
 
 import java.util.ArrayList;
@@ -57,4 +53,6 @@
     private CopyOnWriteArrayList<IMemberModelListener> listeners;
     private OsmDataLayer layer;
+
+    private final int UNCONNECTED = Integer.MIN_VALUE;
 
     /**
@@ -787,4 +785,7 @@
     }
 
+    private Direction determineDirection(int ref_i, Direction ref_direction, int k) {
+        return determineDirection(ref_i, ref_direction, k, false);
+    }
     /**
      * Determines the direction of way k with respect to the way ref_i.
@@ -796,8 +797,8 @@
      * Else the direction is given as follows:
      * Let the relation be a route of oneway streets, and someone travels them in the given order.
-     * Direction is FORWARD if it is legel and BACKWARD if it is illegal to do so for the given way.
+     * Direction is FORWARD if it is legal and BACKWARD if it is illegal to do so for the given way.
      *
      **/
-    private Direction determineDirection(int ref_i,Direction ref_direction, int k) {
+    private Direction determineDirection(int ref_i, final Direction ref_direction, int k, boolean reversed) {
         if (ref_i < 0 || k < 0 || ref_i >= members.size() || k >= members.size())
             return NONE;
@@ -805,6 +806,6 @@
             return NONE;
 
-        RelationMember m_ref = members.get(ref_i);
-        RelationMember m = members.get(k);
+        final RelationMember m_ref = members.get(ref_i);
+        final RelationMember m = members.get(k);
         Way way_ref = null;
         Way way = null;
@@ -847,4 +848,17 @@
                     if (n == nn)
                         return roundaboutType(k);
+                }
+            } else if(isOneway(m)) {
+                if (n == RelationNodeMap.firstOnewayNode(m) && !reversed) {
+                    if(isBackward(m))
+                        return BACKWARD;
+                    else
+                        return FORWARD;
+                }
+                if (n == RelationNodeMap.lastOnewayNode(m) && reversed) {
+                    if(isBackward(m))
+                        return FORWARD;
+                    else
+                        return BACKWARD;
                 }
             } else {
@@ -932,5 +946,5 @@
     public void updateLinks() {
         connectionType = null;
-        ArrayList<WayConnectionType> con = new ArrayList<WayConnectionType>();
+        final List<WayConnectionType> con = new ArrayList<WayConnectionType>();
 
         for (int i=0; i<members.size(); ++i) {
@@ -939,68 +953,73 @@
 
         int firstGroupIdx=0;
-        boolean resetFirstGoupIdx=false;
+
+        lastForwardWay = UNCONNECTED;
+        lastBackwardWay = UNCONNECTED;
+        onewayBeginning = false;
+        WayConnectionType lastWct = null;
 
         for (int i=0; i<members.size(); ++i) {
-            if (resetFirstGoupIdx) {
-                firstGroupIdx = i;
-                resetFirstGoupIdx = false;
-            }
-
-            RelationMember m = members.get(i);
+            final RelationMember m = members.get(i);
             if (! m.isWay()) {
                 con.set(i, new WayConnectionType());
-                resetFirstGoupIdx = true;
+                firstGroupIdx = i;
                 continue;
             }
 
-            Way w = m.getWay();
+            final Way w = m.getWay();
             if (w == null || w.isIncomplete()) {
                 con.set(i, new WayConnectionType());
-                resetFirstGoupIdx = true;
+                firstGroupIdx = i;
                 continue;
             }
-
-            boolean linkPrev = (i != firstGroupIdx);
-            boolean linkNext;
-            Direction dir;
-            if (linkPrev) {
-                dir = determineDirection(i-1, con.get(i-1).direction, i);
-                linkNext = (determineDirection(i, dir, i+1) != NONE);
-            }
-            else {
-                if (roundaboutType(i) != NONE) {
-                    dir = determineDirection(i, roundaboutType(i), i+1) != NONE ? roundaboutType(i) : NONE;
-                } else { /** guess the direction and see if it fits with the next member */
-                    dir = determineDirection(i, FORWARD, i+1) != NONE ? FORWARD : NONE;
-                    if (dir == NONE) {
-                        dir = determineDirection(i, BACKWARD, i+1) != NONE ? BACKWARD : NONE;
-                    }
+          
+            WayConnectionType wct = new WayConnectionType(false);
+            wct.linkPrev = i>0 && con.get(i-1) != null && con.get(i-1).isValid();
+            wct.direction = NONE;
+
+            if(isOneway(m)){
+                if(lastWct != null && lastWct.isOnewayTail)
+                    wct.isOnewayHead = true;
+                if(lastBackwardWay == UNCONNECTED && lastForwardWay == UNCONNECTED){ //Beginning of new oneway
+                    wct.isOnewayHead = true;
+                    lastForwardWay = i-1;
+                    lastBackwardWay = i;
+                    onewayBeginning = true;
                 }
-                linkNext = (dir != NONE);
-                if (dir == NONE) {
-                    if (roundaboutType(i) != NONE) {
-                        dir = roundaboutType(i);
-                    }
+            }            
+
+            if (wct.linkPrev) {
+                if(lastBackwardWay != UNCONNECTED && lastForwardWay != UNCONNECTED) {
+                    wct = determineOnewayConnectionType(con, m, i, wct);
+                    if(!wct.linkPrev)
+                        firstGroupIdx = i;
                 }
 
-            }
-
-            con.set(i, new WayConnectionType(linkPrev, linkNext, dir));
-
-            if (! linkNext) {
-                boolean loop;
-                if (i == firstGroupIdx) {
-                    loop = determineDirection(i, FORWARD, i) == FORWARD;
-                } else {
-                    loop = determineDirection(i, dir, firstGroupIdx) == con.get(firstGroupIdx).direction;
+                if(!isOneway(m)) {
+                    wct.direction = determineDirection(i-1, lastWct.direction, i);
+                    wct.linkPrev = (wct.direction != NONE);
+                }                   
+            }
+            
+            if (!wct.linkPrev) {
+                wct.direction = determineDirectionOfFirst(i, m);
+                if(isOneway(m)){
+                    wct.isOnewayLoopForwardPart = true;
+                    lastForwardWay = i;
                 }
-                if (loop) {
-                    for (int j=firstGroupIdx; j <= i; ++j) {
-                        con.get(j).isLoop = true;
-                    }
-                }
-                resetFirstGoupIdx = true;
-            }
-        }
+            }
+
+            wct.linkNext = false;
+            if(lastWct != null)
+                lastWct.linkNext = wct.linkPrev;
+            con.set(i, wct);
+            lastWct = wct;
+
+            if(!wct.linkPrev) {
+                if(i > 0) makeLoopIfNeeded(con, i-1, firstGroupIdx);
+                firstGroupIdx = i;
+            }
+        }
+        makeLoopIfNeeded(con, members.size()-1, firstGroupIdx);
         connectionType = con;
         //        for (int i=0; i<con.size(); ++i) {
@@ -1008,3 +1027,123 @@
         //        }
     }
+
+//    private static void unconnectPreviousLink(List<WayConnectionType> con, int beg, boolean backward){
+//        int i = beg;
+//        while(true){
+//            WayConnectionType t = con.get(i--);
+//            t.isOnewayOppositeConnected = false;
+//            if(backward && t.isOnewayLoopBackwardPart) break;
+//            if(!backward && t.isOnewayLoopForwardPart) break;
+//        }
+//    }
+
+    private static Direction reverse(final Direction dir){
+        if(dir == FORWARD) return BACKWARD;
+        if(dir == BACKWARD) return FORWARD;
+        return dir;
+    }
+
+    private static boolean isBackward(final RelationMember member){
+        return member.getRole().equals("backward");
+    }
+
+    private static boolean isForward(final RelationMember member){
+        return member.getRole().equals("forward");
+    }
+    
+    public static boolean isOneway(final RelationMember member){
+        return isForward(member) || isBackward(member);
+    }
+
+    private void makeLoopIfNeeded(final List<WayConnectionType> con, final int i, final int firstGroupIdx) {
+        boolean loop;
+        if (i == firstGroupIdx) { //is primitive loop
+            loop = determineDirection(i, FORWARD, i) == FORWARD;
+        } else {
+            loop = determineDirection(i, con.get(i).direction, firstGroupIdx) == con.get(firstGroupIdx).direction;
+        }
+        if (loop) {
+            for (int j=firstGroupIdx; j <= i; ++j) {
+                con.get(j).isLoop = true;
+            }
+        }
+    }
+
+    private Direction determineDirectionOfFirst(final int i, final RelationMember m) {
+        if (roundaboutType(i) != NONE) {
+            return roundaboutType(i);
+        }
+        
+        if (isOneway(m)){
+            if(isBackward(m)) return BACKWARD;
+            else return FORWARD;
+        } else { /** guess the direction and see if it fits with the next member */
+            if(determineDirection(i, FORWARD, i+1) != NONE) return FORWARD;
+            if(determineDirection(i, BACKWARD, i+1) != NONE) return BACKWARD;
+        }
+        return NONE;
+    }
+
+    int lastForwardWay, lastBackwardWay;
+    boolean onewayBeginning;
+    private WayConnectionType determineOnewayConnectionType(final List<WayConnectionType> con,
+            RelationMember m, int i, final WayConnectionType wct) {
+        Direction dirFW = determineDirection(lastForwardWay, con.get(lastForwardWay).direction, i);
+        Direction dirBW = NONE;
+        if(onewayBeginning) {
+            if(lastBackwardWay != i)
+                dirBW = determineDirection(lastBackwardWay, reverse(con.get(lastBackwardWay).direction), i, true);
+            if(dirBW != NONE)
+                onewayBeginning = false;
+        } else
+            dirBW = determineDirection(lastBackwardWay, con.get(lastBackwardWay).direction, i, true);
+
+        if(isOneway(m)) {
+            if(dirBW != NONE){
+                wct.direction = dirBW;
+                lastBackwardWay = i;
+                wct.isOnewayLoopBackwardPart = true;
+            }
+            if(dirFW != NONE){
+                wct.direction = dirFW;
+                lastForwardWay = i;
+                wct.isOnewayLoopForwardPart = true;
+            }
+            if(dirFW == NONE && dirBW == NONE) { //Not connected to previous
+//                        unconnectPreviousLink(con, i, true);
+//                        unconnectPreviousLink(con, i, false);
+                wct.linkPrev = false;
+                if(isOneway(m)){
+                    wct.isOnewayHead = true;
+                    lastForwardWay = i-1;
+                    lastBackwardWay = i;
+                } else {
+                    lastForwardWay = UNCONNECTED;
+                    lastBackwardWay = UNCONNECTED;
+                }
+                onewayBeginning = true;
+            }
+
+            if(dirFW != NONE && dirBW != NONE) { //End of oneway loop
+                if(i+1<members.size() && determineDirection(i, dirFW, i+1) != NONE) {
+                    wct.isOnewayLoopBackwardPart = false;
+                    dirBW = NONE;
+                    wct.direction = dirFW;
+                } else {
+                    wct.isOnewayLoopForwardPart = false;
+                    dirFW = NONE;
+                    wct.direction = dirBW;
+                }
+
+                wct.isOnewayTail = true;
+            }
+
+        } else {
+            lastForwardWay = UNCONNECTED;
+            lastBackwardWay = UNCONNECTED;
+            if(dirFW == NONE || dirBW == NONE)
+                wct.linkPrev = false;
+        }
+        return wct;
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/relation/RelationNodeMap.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/relation/RelationNodeMap.java	(revision 3787)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/relation/RelationNodeMap.java	(revision 3788)
@@ -5,7 +5,7 @@
 
 import java.util.ArrayList;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.TreeMap;
 import java.util.TreeSet;
@@ -30,13 +30,28 @@
  */
 public class RelationNodeMap {
+    private class NodesWays{
+        public Map<Node, Set<Integer>> nodes = new TreeMap<Node, Set<Integer>>();
+        public Map<Integer, Set<Node>> ways = new TreeMap<Integer, Set<Node>>();
+        public boolean oneWay;
+        public NodesWays(boolean oneWay){
+            this.oneWay = oneWay;
+        }
+    }
+
     /*
      * the maps. (Need TreeMap for efficiency.)
      */
-    private TreeMap<Node, TreeSet<Integer>> nodesMap;
-    private TreeMap<Integer, TreeSet<Node>> waysMap;
+    private NodesWays map = new NodesWays(false);
+    /*
+     * Maps for oneways (forward/backward roles)
+     */
+
+    private NodesWays onewayMap = new NodesWays(true);
+    private NodesWays onewayReverseMap = new NodesWays(true);
     /*
      * Used to keep track of what members are done.
      */
-    private TreeSet<Integer> remaining;
+    private Set<Integer> remaining;
+    private Map<Integer, Set<Node>> remainingOneway = new TreeMap<Integer, Set<Node>>();;
 
     /**
@@ -45,31 +60,47 @@
     private List<Integer> notSortable = new ArrayList<Integer>();
 
+    public static Node firstOnewayNode(RelationMember m){
+        if(!m.isWay()) return null;
+        if(m.getRole().equals("backward")) return m.getWay().lastNode();
+        return m.getWay().firstNode();
+    }
+
+    public static Node lastOnewayNode(RelationMember m){
+        if(!m.isWay()) return null;
+        if(m.getRole().equals("backward")) return m.getWay().firstNode();
+        return m.getWay().lastNode();
+    }
+
     RelationNodeMap(List<RelationMember> members) {
-        nodesMap = new TreeMap<Node, TreeSet<Integer>>();
-        waysMap = new TreeMap<Integer, TreeSet<Node>>();
+        map.nodes = new TreeMap<Node, Set<Integer>>();
+        map.ways = new TreeMap<Integer, Set<Node>>();
 
         for (int i = 0; i < members.size(); ++i) {
             RelationMember m = members.get(i);
-            if (m.getMember().isIncomplete() || !m.isWay())
-            {
+            if (m.getMember().isIncomplete() || !m.isWay()) {
                 notSortable.add(i);
-            }
-            else {
-                Way w = m.getWay();
-                if (MemberTableModel.roundaboutType(w) != NONE) {
-                    for (Node nd : w.getNodes()) {
-                        addPair(nd, i);
-                    }
-                } else {
-                    addPair(w.firstNode(), i);
-                    addPair(w.lastNode(), i);
-                }
+                continue;
+            }
+
+            Way w = m.getWay();
+            if ((MemberTableModel.roundaboutType(w) != NONE)) {
+                for (Node nd : w.getNodes()) {
+                    addPair(nd, i);
+                }
+            } else if(MemberTableModel.isOneway(m)) {
+                addNodeWayMap(firstOnewayNode(m), i);
+                addWayNodeMap(lastOnewayNode(m), i);
+                addNodeWayMapReverse(lastOnewayNode(m), i);
+                addWayNodeMapReverse(firstOnewayNode(m), i);
+                addRemainingForward(firstOnewayNode(m), i);
+                addRemainingForward(lastOnewayNode(m), i);
+            } else {
+                addPair(w.firstNode(), i);
+                addPair(w.lastNode(), i);
             }
         }
 
         remaining = new TreeSet<Integer>();
-        for (Integer k : waysMap.keySet()) {
-            remaining.add(k);
-        }
+        remaining.addAll(map.ways.keySet());
 
         /*
@@ -77,54 +108,203 @@
          * cannot be used in future. (only for performance)
          */
-        Iterator<Map.Entry<Node,TreeSet<Integer>>> it = nodesMap.entrySet().iterator();
-        while (it.hasNext()) {
-            Map.Entry<Node,TreeSet<Integer>> nodeLinks = it.next();
-
-            if (nodeLinks.getValue().size() < 2) {
-                if (nodeLinks.getValue().size() != 1) throw new AssertionError();
-
-                Integer d_way = nodeLinks.getValue().iterator().next();
-                TreeSet<Node> d_way_nodes = waysMap.get(d_way);
-                d_way_nodes.remove(nodeLinks.getKey());
-
-                it.remove();
-                continue;
-            }
-        }
-    }
+//        Iterator<Map.Entry<Node,TreeSet<Integer>>> it = map.nodes.entrySet().iterator();
+//        while (it.hasNext()) {
+//            Map.Entry<Node,TreeSet<Integer>> nodeLinks = it.next();
+//
+//            if (nodeLinks.getValue().size() < 2) {
+//                if (nodeLinks.getValue().size() != 1) throw new AssertionError();
+//
+//                Integer d_way = nodeLinks.getValue().iterator().next();
+//                TreeSet<Node> d_way_nodes = map.ways.get(d_way);
+//                d_way_nodes.remove(nodeLinks.getKey());
+//
+//                it.remove();
+//                continue;
+//            }
+//        }
+            }
 
     private void addPair(Node n, int i) {
-        TreeSet<Integer> ts = nodesMap.get(n);
+        Set<Integer> ts = map.nodes.get(n);
         if (ts == null) {
             ts = new TreeSet<Integer>();
-            nodesMap.put(n, ts);
+            map.nodes.put(n, ts);
         }
         ts.add(i);
 
-        TreeSet<Node> ts2 = waysMap.get(i);
+        Set<Node> ts2 = map.ways.get(i);
         if (ts2 == null) {
             ts2 = new TreeSet<Node>();
-            waysMap.put(i, ts2);
+            map.ways.put(i, ts2);
         }
         ts2.add(n);
     }
 
+    private void addNodeWayMap(Node n, int i) {
+        Set<Integer> ts = onewayMap.nodes.get(n);
+        if (ts == null) {
+            ts = new TreeSet<Integer>();
+            onewayMap.nodes.put(n, ts);
+        }
+        ts.add(i);
+    }
+
+    private void addWayNodeMap(Node n, int i) {
+        Set<Node> ts2 = onewayMap.ways.get(i);
+        if (ts2 == null) {
+            ts2 = new TreeSet<Node>();
+            onewayMap.ways.put(i, ts2);
+        }
+        ts2.add(n);
+    }
+
+    private void addNodeWayMapReverse(Node n, int i) {
+        Set<Integer> ts = onewayReverseMap.nodes.get(n);
+        if (ts == null) {
+            ts = new TreeSet<Integer>();
+            onewayReverseMap.nodes.put(n, ts);
+        }
+        ts.add(i);
+    }
+
+    private void addWayNodeMapReverse(Node n, int i) {
+        Set<Node> ts2 = onewayReverseMap.ways.get(i);
+        if (ts2 == null) {
+            ts2 = new TreeSet<Node>();
+            onewayReverseMap.ways.put(i, ts2);
+        }
+        ts2.add(n);
+    }
+
+    private void addRemainingForward(Node n, int i) {
+        Set<Node> ts2 = remainingOneway.get(i);
+        if (ts2 == null) {
+            ts2 = new TreeSet<Node>();
+            remainingOneway.put(i, ts2);
+        }
+        ts2.add(n);
+    }
+
+    Integer firstOneway = null;
+    Node lastOnewayNode = null;
+    Node firstCircular = null;
+
     /**
      * Return a relation member that is linked to the
-     * member 'i', but has not been popped jet.
+     * member 'i', but has not been popped yet.
      * Return null if there is no such member left.
      */
-    public Integer popAdjacent(Integer i) {
-        TreeSet<Node> nodes = waysMap.get(i);
-        for (Node n : nodes) {
-            TreeSet<Integer> adj = nodesMap.get(n);
-            if (!adj.isEmpty()) {
-                Integer j = adj.iterator().next();
-                done(j);
-                waysMap.get(j).remove(n);
-                return j;
-            }
-        }
+    public Integer popAdjacent(Integer way) {
+        if (lastOnewayNode != null) return popBackwardOnewayPart(way);
+        if (firstOneway != null) return popForwardOnewayPart(way);
+
+        if (map.ways.containsKey(way)){
+            for (Node n : map.ways.get(way)) {
+                Integer i = deleteAndGetAdjacentNode(map, n);
+                if(i != null) return i;
+
+                Integer j = deleteAndGetAdjacentNode(onewayMap, n);
+                if(j != null) {
+                    firstOneway = j;
+                    return j;
+                }
+            }
+        }
+        
+        firstOneway = way;
+        return popForwardOnewayPart(way);
+    }
+
+    private Integer popForwardOnewayPart(Integer way) {
+        if(onewayMap.ways.containsKey(way)) {
+            for (Node n : onewayMap.ways.get(way)) {
+                Integer i = findAdjacentWay(onewayMap, n);
+                if(i == null) continue;
+
+                lastOnewayNode = processBackwardIfEndOfLoopReached(i);
+                if(lastOnewayNode != null){
+                    return popBackwardOnewayPart(firstOneway);
+                }
+
+                deleteWayNode(onewayMap, i, n);
+                return i;
+            }
+        }
+        
+        firstOneway = null;
         return null;
+    }
+
+    private Node processBackwardIfEndOfLoopReached(Integer way) { //find if we didn't reach end of the loop (and process backward part)
+        if (onewayReverseMap.ways.containsKey(way)) {
+            for (Node n : onewayReverseMap.ways.get(way)) {
+                if((map.nodes.containsKey(n))
+                        || (onewayMap.nodes.containsKey(n) && onewayMap.nodes.get(n).size() > 1)) {
+                    return n;
+                }
+                if(firstCircular != null && firstCircular == n) {
+                    return firstCircular;
+                }
+            }
+        }
+        return null;
+    }
+    
+    private Integer popBackwardOnewayPart(int way){
+        if (lastOnewayNode != null) {
+            TreeSet<Node> nodes = new TreeSet<Node>();
+            if (onewayReverseMap.ways.containsKey(way)) nodes.addAll(onewayReverseMap.ways.get(way));
+            if (map.ways.containsKey(way)) nodes.addAll(map.ways.get(way));
+            for (Node n : nodes) {
+                if(n == lastOnewayNode) { //if oneway part ends
+                    firstOneway = null;
+                    lastOnewayNode = null;
+                    Integer j = deleteAndGetAdjacentNode(map, n);
+                    if(j != null) return j;
+
+                    Integer k = deleteAndGetAdjacentNode(onewayMap, n);
+                    if(k != null) {
+                        firstOneway = k;
+                        return k;
+                    }
+                }
+
+                Integer j = deleteAndGetAdjacentNode(onewayReverseMap, n);
+                if(j != null) return j;
+            }
+        }
+
+        firstOneway = null;
+        lastOnewayNode = null;
+        
+        return null;
+    }
+
+    /**
+     * find next node in nw NodeWays structure, if the node is found delete and return it
+     * @param nw
+     * @param n
+     * @return node next to n
+     */
+    private Integer deleteAndGetAdjacentNode(NodesWays nw, Node n){
+        Integer j = findAdjacentWay(nw, n);
+        if(j == null) return null;
+        deleteWayNode(nw, j, n);
+        return j;
+    }
+
+    private Integer findAdjacentWay(NodesWays nw, Node n) {
+        Set<Integer> adj = nw.nodes.get(n);
+        if (adj == null || adj.isEmpty()) return null;
+        Integer j = adj.iterator().next();
+        return j;
+    }
+
+    private void deleteWayNode(NodesWays nw, Integer way, Node n){
+        if(nw.oneWay)
+            doneOneway(way);
+        else
+            done(way);
+        nw.ways.get(way).remove(n);
     }
 
@@ -134,7 +314,23 @@
      */
     public Integer pop() {
-        if (remaining.isEmpty()) return null;
-        Integer i = remaining.iterator().next();
-        done(i);
+        if (!remaining.isEmpty()){
+            Integer i = remaining.iterator().next();
+            done(i);
+            return i;
+        }
+
+        if (remainingOneway.isEmpty()) return null;
+        for(Integer i :remainingOneway.keySet()){ //find oneway, whic is connected to more than one way (is between two oneway loops)
+            for(Node n : onewayReverseMap.ways.get(i)){
+                if(onewayReverseMap.nodes.containsKey(n) && onewayReverseMap.nodes.get(n).size() > 1) {
+                    doneOneway(i);
+                    firstCircular = n;
+                    return i;
+                }
+            }
+        }
+
+        Integer i = remainingOneway.keySet().iterator().next();
+        doneOneway(i);
         return i;
     }
@@ -142,11 +338,20 @@
     /**
      * This relation member has been processed.
-     * Remove references in the nodesMap.
-     */
+     * Remove references in the map.nodes.
+     */
+    private void doneOneway(Integer i) {
+        Set<Node> nodesForward = remainingOneway.get(i);
+        for (Node n : nodesForward) {
+            if(onewayMap.nodes.containsKey(n)) onewayMap.nodes.get(n).remove(i);
+            if(onewayReverseMap.nodes.containsKey(n)) onewayReverseMap.nodes.get(n).remove(i);
+        }
+        remainingOneway.remove(i);
+    }
+
     private void done(Integer i) {
         remaining.remove(i);
-        TreeSet<Node> nodes = waysMap.get(i);
+        Set<Node> nodes = map.ways.get(i);
         for (Node n : nodes) {
-            boolean result = nodesMap.get(n).remove(i);
+            boolean result = map.nodes.get(n).remove(i);
             if (!result) throw new AssertionError();
         }
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/relation/WayConnectionType.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/relation/WayConnectionType.java	(revision 3787)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/relation/WayConnectionType.java	(revision 3788)
@@ -11,6 +11,6 @@
 
     /** True, if linked to the previous / next member.  */
-    public final boolean linkPrev;
-    public final boolean linkNext;
+    public boolean linkPrev;
+    public boolean linkNext;
 
     /**
@@ -23,5 +23,5 @@
      * direction has the value NONE.
      */
-    public final Direction direction;
+    public Direction direction;
 
     public enum Direction {
@@ -36,5 +36,9 @@
     public boolean isLoop;
 
-    public boolean isRoundabout = false;
+    public boolean isOnewayLoopForwardPart = false;
+    public boolean isOnewayLoopBackwardPart = false;
+    public boolean isOnewayHead = false;
+    public boolean isOnewayTail = false;
+//    public boolean isOnewayOppositeConnected = true;
 
     public WayConnectionType(boolean linkPrev, boolean linkNext, Direction direction) {
@@ -44,4 +48,8 @@
         this.direction = direction;
         invalid = false;
+    }
+
+    public WayConnectionType(boolean invalid){
+        this.invalid = invalid;
     }
 
@@ -61,5 +69,7 @@
     @Override
     public String toString() {
-        return "[P "+linkPrev+" ;N "+linkNext+" ;D "+direction+" ;L "+isLoop+"]";
+        return "[P "+linkPrev+" ;N "+linkNext+" ;D "+direction+" ;L "+isLoop+
+                " ;FP " + isOnewayLoopForwardPart+";BP " + isOnewayLoopBackwardPart+
+                ";OH " + isOnewayHead+";OT " + isOnewayTail+"]";
     }
 
