Index: src/terracer/HouseNumberInputDialog.java
===================================================================
--- src/terracer/HouseNumberInputDialog.java	(revision 24695)
+++ src/terracer/HouseNumberInputDialog.java	(working copy)
@@ -15,6 +15,8 @@
 import java.awt.Dimension;
 import java.awt.GridBagConstraints;
 import java.awt.GridBagLayout;
+import java.util.ArrayList;
+import java.util.Iterator;
 import java.awt.event.ActionEvent;
 import java.util.TreeSet;
 
@@ -26,6 +28,7 @@
 import javax.swing.JTextField;
 
 import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.osm.Node;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.Way;
 import org.openstreetmap.josm.gui.ExtendedDialog;
@@ -54,7 +57,9 @@
     final static String INTERPOLATION = "plugins.terracer.interpolation";
 
     final private Way street;
+    final private String streetName;
     final private boolean relationExists;
+    final ArrayList<Node> housenumbers;
 
     protected static final String DEFAULT_MESSAGE = tr("Enter housenumbers or amount of segments");
     private static final long serialVersionUID = 1L;
@@ -64,6 +69,8 @@
     JTextField lo;
     private JLabel hiLabel;
     JTextField hi;
+    private JLabel numbersLabel;
+    JTextField numbers;
     private JLabel streetLabel;
     AutoCompletingComboBox streetComboBox;
     private JLabel segmentsLabel;
@@ -79,9 +86,13 @@
     /**
      * @param street If street is not null, we assume, the name of the street to be fixed
      * and just show a label. If street is null, we show a ComboBox/InputField.
+     * @param streetName the name of the street, derived from either the
+     *        street line or the house numbers which are guaranteed to have the
+     *        same name attached (may be null)
      * @param relationExists If the buildings can be added to an existing relation or not.
+     * @param housenumbers a list of house numbers in this outline (may be empty)
      */
-    public HouseNumberInputDialog(HouseNumberInputHandler handler, Way street, boolean relationExists) {
+    public HouseNumberInputDialog(HouseNumberInputHandler handler, Way street, String streetName, boolean relationExists, ArrayList<Node> housenumbers) {
         super(Main.parent,
                 tr("Terrace a house"),
                 new String[] { tr("OK"), tr("Cancel")},
@@ -89,7 +100,9 @@
         );
         this.inputHandler = handler;
         this.street = street;
+        this.streetName = streetName;
         this.relationExists = relationExists;
+        this.housenumbers = housenumbers;
         handler.dialog = this;
         JPanel content = getInputPanel();
         setContent(content);
@@ -159,6 +172,9 @@
             loLabel.setToolTipText(tr("Lowest housenumber of the terraced house"));
             hiLabel = new JLabel();
             hiLabel.setText(tr("Highest Number"));
+            numbersLabel = new JLabel();
+            numbersLabel.setText(tr("List of Numbers"));
+            loLabel.setPreferredSize(new Dimension(111, 16));
             final String txt = relationExists ? tr("add to existing associatedStreet relation") : tr("create an associatedStreet relation");
 
             handleRelationCheckBox = new JCheckBox(txt, Main.pref.getBoolean(HANDLE_RELATION, true));
@@ -174,18 +190,35 @@
             inputPanel.add(getLo(), GBC.eol().fill(GBC.HORIZONTAL).insets(5,3,0,0));
             inputPanel.add(hiLabel, GBC.std().insets(3,3,0,0));
             inputPanel.add(getHi(), GBC.eol().fill(GBC.HORIZONTAL).insets(5,3,0,0));
+            inputPanel.add(numbersLabel, GBC.std().insets(3,3,0,0));
+            inputPanel.add(getNumbers(), GBC.eol().fill(GBC.HORIZONTAL).insets(5,3,0,0));
             inputPanel.add(interpolationLabel, GBC.std().insets(3,3,0,0));
             inputPanel.add(getInterpolation(), GBC.eol().insets(5,3,0,0));
             inputPanel.add(segmentsLabel, GBC.std().insets(3,3,0,0));
             inputPanel.add(getSegments(), GBC.eol().fill(GBC.HORIZONTAL).insets(5,3,0,0));
-            if (street == null) {
+            if (streetName == null) {
                 inputPanel.add(streetLabel, GBC.std().insets(3,3,0,0));
                 inputPanel.add(getStreet(), GBC.eol().insets(5,3,0,0));
             } else {
-                inputPanel.add(new JLabel(tr("Street name: ")+"\""+street.get("name")+"\""), GBC.eol().insets(3,3,0,0));
+                inputPanel.add(new JLabel(tr("Street name: ")+"\""+streetName+"\""), GBC.eol().insets(3,3,0,0));
             }
             inputPanel.add(handleRelationCheckBox, GBC.eol().insets(3,3,0,0));
             inputPanel.add(deleteOutlineCheckBox, GBC.eol().insets(3,3,0,0));
+            
+            if (numbers.isVisible())
+            {
+                loLabel.setVisible(false);
+                lo.setVisible(false);
+                lo.setEnabled(false);
+                hiLabel.setVisible(false);
+                hi.setVisible(false);
+                hi.setEnabled(false);
+                interpolationLabel.setVisible(false);
+                interpolation.setVisible(false);
+                interpolation.setEnabled(false);
+                segments.setText(String.valueOf(housenumbers.size()));
+                segments.setEditable(false);
+            }
         }
         return inputPanel;
     }
@@ -223,6 +256,33 @@
         }
         return hi;
     }
+    
+    /**
+     * This method initializes numbers
+     *
+     * @return javax.swing.JTextField
+     */
+    private JTextField getNumbers() {
+        if (numbers == null) {
+            numbers = new JTextField();
+            
+            Iterator<Node> it = housenumbers.iterator();
+            StringBuilder s = new StringBuilder(256);
+            if (it.hasNext()) {
+                s.append(it.next().get("addr:housenumber"));
+                while (it.hasNext())
+                    s.append(';').append(it.next().get("addr:housenumber"));
+            }
+            else {
+                numbersLabel.setVisible(false);
+                numbers.setVisible(false);
+            }
+            
+            numbers.setText(s.toString());
+            numbers.setEditable(false);
+        }
+        return numbers;
+    }
 
     /**
      * This method initializes street
Index: src/terracer/TerracerAction.java
===================================================================
--- src/terracer/TerracerAction.java	(revision 24695)
+++ src/terracer/TerracerAction.java	(working copy)
@@ -15,9 +15,15 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Map.Entry;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 import javax.swing.JOptionPane;
 
@@ -30,6 +36,7 @@
 import org.openstreetmap.josm.command.DeleteCommand;
 import org.openstreetmap.josm.command.SequenceCommand;
 import org.openstreetmap.josm.data.coor.LatLon;
+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;
@@ -40,16 +47,16 @@
 import org.openstreetmap.josm.tools.Shortcut;
 
 /**
- * Terraces a quadrilateral, closed way into a series of quadrilateral,
- * closed ways. If two ways are selected and one of them can be identified as
- * a street (highway=*, name=*) then the given street will be added
- * to the 'associatedStreet' relation.
- *
- *
- * At present it only works on quadrilaterals, but there is no reason
- * why it couldn't be extended to work with other shapes too. The
- * algorithm employed is naive, but it works in the simple case.
- *
+ * Terraces a quadrilateral, closed way into a series of quadrilateral, closed
+ * ways. If two ways are selected and one of them can be identified as a street
+ * (highway=*, name=*) then the given street will be added to the
+ * 'associatedStreet' relation.
+ * 
+ * 
+ * At present it only works on quadrilaterals, but there is no reason why it
+ * couldn't be extended to work with other shapes too. The algorithm employed is
+ * naive, but it works in the simple case.
+ * 
  * @author zere
  */
 public final class TerracerAction extends JosmAction {
@@ -77,43 +84,91 @@
                 .getSelected();
         Way outline = null;
         Way street = null;
+        String streetname = null;
+        ArrayList<Node> housenumbers = new ArrayList<Node>();
 
         class InvalidUserInputException extends Exception {
             InvalidUserInputException(String message) {
                 super(message);
             }
+
             InvalidUserInputException() {
                 super();
             }
         }
 
         try {
-            if (sel.size() == 2) {
-                Iterator<OsmPrimitive> it = sel.iterator();
-                OsmPrimitive prim1 = it.next();
-                OsmPrimitive prim2 = it.next();
-                if (!(prim1 instanceof Way && prim2 instanceof Way))
-                    throw new InvalidUserInputException();
-                Way way1 = (Way) prim1;
-                Way way2 = (Way) prim2;
-                if (way2.get("highway") != null) {
-                    street = way2;
-                    outline = way1;
-                } else if (way1.get("highway") != null) {
-                    street = way1;
-                    outline = way2;
-                } else
-                    throw new InvalidUserInputException();
-                if (street.get("name") == null)
-                    throw new InvalidUserInputException();
-
-            } else if (sel.size() == 1) {
+            if (sel.size() == 1) {
                 OsmPrimitive prim = sel.iterator().next();
 
                 if (!(prim instanceof Way))
                     throw new InvalidUserInputException();
 
-                outline = (Way)prim;
+                outline = (Way) prim;
+            } else if (sel.size() > 1) {
+                List<Way> ways = OsmPrimitive.getFilteredList(sel, Way.class);
+                Iterator<Way> wit = ways.iterator();
+                while (wit.hasNext()) {
+                    Way way = wit.next();
+                    String type = way.get("building");
+                    if (type != null) {
+                        if (outline == null)
+                            outline = way;
+                        else
+                            // already have a building
+                            throw new InvalidUserInputException();
+                    } else if ((type = way.get("highway")) != null) {
+                        if (street == null)
+                            street = way;
+                        else
+                            // already have a street
+                            throw new InvalidUserInputException();
+
+                        if ((streetname = street.get("name")) == null)
+                            throw new InvalidUserInputException();
+                    } else
+                        throw new InvalidUserInputException();
+                }
+
+                if (outline == null)
+                    throw new InvalidUserInputException();
+
+                List<Node> nodes = OsmPrimitive
+                        .getFilteredList(sel, Node.class);
+                Iterator<Node> nit = nodes.iterator();
+                // Actually this should test if the selected address nodes lies
+                // within
+                // within the selected outline. Any ideas how to do this?
+                while (nit.hasNext()) {
+                    Node node = nit.next();
+                    if (node.get("addr:housenumber") != null) {
+                        String nodesstreetname = node.get("addr:street");
+                        // if a node has a street name if must be equal
+                        // to the one of the other address nodes
+                        if (nodesstreetname != null) {
+                            if (streetname == null)
+                                streetname = nodesstreetname;
+                            else if (!nodesstreetname.equals(streetname))
+                                throw new InvalidUserInputException();
+                        }
+                        // if a node has a street name it must be
+                        // equal to the one of the street line
+                        if (nodesstreetname != null && street != null
+                                && !nodesstreetname.equals(street.get("name")))
+                            throw new InvalidUserInputException();
+
+                        housenumbers.add(node);
+                    } else {
+                        // A given node might not be an address node but then
+                        // it should be part of the building or the street line.
+                        if (!outline.containsNode(node)
+                                && !(street != null && street
+                                        .containsNode(node)))
+                            throw new InvalidUserInputException();
+                    }
+                }
+
+                Collections.sort(housenumbers, new HousenumberNodeComparator());
             } else
                 throw new InvalidUserInputException();
 
@@ -128,16 +183,21 @@
             return;
         }
 
-        // If we have a street, try to find a associatedStreet relation that could be reused.
+        // If we have a street, try to find an associatedStreet relation that
+        // could be reused.
         Relation associatedStreet = null;
         if (street != null) {
-            outer:for (OsmPrimitive osm : Main.main.getCurrentDataSet().allNonDeletedPrimitives()) {
-                if (!(osm instanceof Relation)) continue;
+            outer: for (OsmPrimitive osm : Main.main.getCurrentDataSet()
+                    .allNonDeletedPrimitives()) {
+                if (!(osm instanceof Relation))
+                    continue;
                 Relation rel = (Relation) osm;
-                if ("associatedStreet".equals(rel.get("type")) && street.get("name").equals(rel.get("name"))) {
+                if ("associatedStreet".equals(rel.get("type"))
+                        && street.get("name").equals(rel.get("name"))) {
                     List<RelationMember> members = rel.getMembers();
                     for (RelationMember m : members) {
-                        if ("street".equals(m.getRole()) && m.isWay() && m.getMember().equals(street)) {
+                        if ("street".equals(m.getRole()) && m.isWay()
+                                && m.getMember().equals(street)) {
                             associatedStreet = rel;
                             break outer;
                         }
@@ -146,9 +206,31 @@
             }
         }
 
-        String title = trn("Change {0} object", "Change {0} objects", sel.size(), sel.size());
-        // show input dialog.
-        new HouseNumberInputHandler(this, outline, street, associatedStreet, title);
+        if (housenumbers.size() == 1) {
+            // Special case of one outline and one address node.
+            // Don't open the dialogue, just copy the node keys
+            // to the outline, set building just in case it isn't there
+            // and remove the node.
+            Collection<Command> commands = new LinkedList<Command>();
+            Way newOutline = new Way(outline);
+            for (Entry<String, String> entry : housenumbers.get(0).getKeys()
+                    .entrySet()) {
+                newOutline.put(entry.getKey(), entry.getValue());
+            }
+            newOutline.put("building", "yes");
+            commands.add(new ChangeCommand(outline, newOutline));
+            commands.add(DeleteCommand.delete(Main.main.getEditLayer(),
+                    housenumbers, true, true));
+            Main.main.undoRedo
+                    .add(new SequenceCommand(tr("Terrace"), commands));
+            Main.main.getCurrentDataSet().setSelected(newOutline);
+        } else {
+            String title = trn("Change {0} object", "Change {0} objects", sel
+                    .size(), sel.size());
+            // show input dialog.
+            new HouseNumberInputHandler(this, outline, street, streetname,
+                    associatedStreet, housenumbers, title);
+        }
     }
 
     public Integer getNumber(String number) {
@@ -160,68 +242,114 @@
     }
 
     /**
+     * Sorts the house number nodes according their numbers only
+     * 
+     * @param house
+     *            number nodes
+     */
+    class HousenumberNodeComparator implements Comparator<Node> {
+        private final Pattern pat = Pattern.compile("^([0-9]+)");
+
+        /*
+         * (non-Javadoc)
+         * 
+         * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
+         */
+        @Override
+        public int compare(Node node1, Node node2) {
+            // It's necessary to strip off trailing non-numbers so we can
+            // compare the numbers itself numerically since string comparison
+            // doesn't work for numbers with different number of digits,
+            // e.g. 9 is higher than 11
+            String node1String = node1.get("addr:housenumber");
+            String node2String = node2.get("addr:housenumber");
+            Matcher mat = pat.matcher(node1String);
+            if (mat.find()) {
+                Integer node1Int = Integer.valueOf(mat.group(1));
+                mat = pat.matcher(node2String);
+                if (mat.find()) {
+                    Integer node2Int = Integer.valueOf(mat.group(1));
+
+                    return node1Int.compareTo(node2Int);
+                }
+            }
+
+            return node1String.compareTo(node2String);
+        }
+    }
+
+    /**
      * Terraces a single, closed, quadrilateral way.
-     *
+     * 
      * Any node must be adjacent to both a short and long edge, we naively
      * choose the longest edge and its opposite and interpolate along them
      * linearly to produce new nodes. Those nodes are then assembled into
      * closed, quadrilateral ways and left in the selection.
-     *
-     * @param outline The closed, quadrilateral way to terrace.
-     * @param street The street, the buildings belong to (may be null)
+     * 
+     * @param outline
+     *            The closed, quadrilateral way to terrace.
+     * @param street
+     *            The street, the buildings belong to (may be null)
      * @param associatedStreet
      * @param From
      * @param To
-     * @param streetName the name of a street (may be null). Used if not null and street is null.
-     * @param handleRelations If the user likes to add a relation or extend an existing relation
-     * @param deleteOutline If the outline way should be deleted, when done
+     * @param streetName
+     *            the name of a street (may be null). Used if not null and
+     *            street is null.
+     * @param handleRelations
+     *            If the user likes to add a relation or extend an existing
+     *            relation
+     * @param streetName
+     *            the name of the street, derived from the street line or the
+     *            house numbers (may be null)
+     * @param housenumbers
+     * @param deleteOutline
+     *            If the outline way should be deleted, when done
      */
-    public void terraceBuilding(Way outline,
-                Way street,
-                Relation associatedStreet,
-                Integer segments,
-                String From,
-                String To,
-                int step,
-                String streetName,
-                boolean handleRelations,
-                boolean deleteOutline) {
+    public void terraceBuilding(Way outline, Way street,
+            Relation associatedStreet, Integer segments, String From,
+            String To, int step, ArrayList<Node> housenumbers,
+            String streetName, boolean handleRelations, boolean deleteOutline) {
         final int nb;
-
-        Integer to, from;
-        to = getNumber(To);
-        from = getNumber(From);
-        if (to != null && from != null) {
-            nb = 1 + (to.intValue() - from.intValue()) / step;
-        } else if (segments != null) {
-            nb = segments.intValue();
+        Integer to = null, from = null;
+        if (housenumbers.isEmpty()) {
+            to = getNumber(To);
+            from = getNumber(From);
+            if (to != null && from != null) {
+                nb = 1 + (to.intValue() - from.intValue()) / step;
+            } else if (segments != null) {
+                nb = segments.intValue();
+            } else {
+                // if we get here, there is is a bug in the input validation.
+                throw new TerracerRuntimeException(
+                        "Could not determine segments from parameters, this is a bug. "
+                                + "Parameters were: segments " + segments
+                                + " from " + from + " to " + to + " step "
+                                + step);
+            }
         } else {
-            // if we get here, there is is a bug in the input validation.
-            throw new TerracerRuntimeException(
-                    "Could not determine segments from parameters, this is a bug. "
-                            + "Parameters were: segments " + segments
-                            + " from " + from + " to " + to + " step " + step);
+            nb = housenumbers.size();
         }
 
+        // now find which is the longest side connecting the first node
+        Pair<Way, Way> interp = findFrontAndBack(outline);
+
+        final double frontLength = wayLength(interp.a);
+        final double backLength = wayLength(interp.b);
+
         // new nodes array to hold all intermediate nodes
         Node[][] new_nodes = new Node[2][nb + 1];
 
         this.commands = new LinkedList<Command>();
         Collection<Way> ways = new LinkedList<Way>();
 
-        // Should this building be terraced (i.e. is there more then one section?)
         if (nb > 1) {
             // create intermediate nodes by interpolating.
-
-            // now find which is the longest side connecting the first node
-            Pair<Way, Way> interp = findFrontAndBack(outline);
-
-            final double frontLength = wayLength(interp.a);
-            final double backLength = wayLength(interp.b);
-
             for (int i = 0; i <= nb; ++i) {
-                new_nodes[0][i] = interpolateAlong(interp.a, frontLength * i / nb);
-                new_nodes[1][i] = interpolateAlong(interp.b, backLength * i / nb);
+                new_nodes[0][i] = interpolateAlong(interp.a, frontLength * i
+                        / nb);
+                new_nodes[1][i] = interpolateAlong(interp.b, backLength * i
+                        / nb);
                 this.commands.add(new AddCommand(new_nodes[0][i]));
                 this.commands.add(new AddCommand(new_nodes[1][i]));
             }
@@ -229,9 +357,6 @@
             // assemble new quadrilateral, closed ways
             for (int i = 0; i < nb; ++i) {
                 Way terr = new Way();
-                // Using Way.nodes.add rather than Way.addNode because the latter
-                // doesn't
-                // exist in older versions of JOSM.
                 terr.addNode(new_nodes[0][i]);
                 terr.addNode(new_nodes[0][i + 1]);
                 terr.addNode(new_nodes[1][i + 1]);
@@ -242,33 +367,46 @@
                 TagCollection.from(outline).applyTo(terr);
 
                 String number = null;
-                if (from != null) {
-                    number = Integer.toString(from + i * step);
+                Set<Entry<String, String>> additionalKeys = null;
+                if (housenumbers.isEmpty()) {
+                    if (from != null) {
+                        // only, if the user has specified house numbers
+                        number = Integer.toString(from + i * step);
+                    }
+                } else {
+                    number = housenumbers.get(i).get("addr:housenumber");
+                    additionalKeys = housenumbers.get(i).getKeys().entrySet();
                 }
-                terr = addressBuilding(terr, street, streetName, number);
 
+                terr = addressBuilding(terr, street, streetName, number,
+                        additionalKeys);
+
                 ways.add(terr);
                 this.commands.add(new AddCommand(terr));
             }
 
             if (deleteOutline) {
-                this.commands.add(DeleteCommand.delete(Main.main.getEditLayer(), Collections.singleton(outline), true, true));
+                this.commands.add(DeleteCommand.delete(
+                        Main.main.getEditLayer(), Collections
+                                .singleton(outline), true, true));
             }
         } else {
-            // Single section, just add the address details
+            // Single building, just add the address details
             Way newOutline;
-            newOutline = addressBuilding(outline, street, streetName, From);
+            newOutline = addressBuilding(outline, street, streetName, From,
+                    null);
             ways.add(newOutline);
             this.commands.add(new ChangeCommand(outline, newOutline));
         }
 
         if (handleRelations) { // create a new relation or merge with existing
-            if (associatedStreet == null) {  // create a new relation
+            if (associatedStreet == null) { // create a new relation
                 associatedStreet = new Relation();
                 associatedStreet.put("type", "associatedStreet");
                 if (street != null) { // a street was part of the selection
                     associatedStreet.put("name", street.get("name"));
-                    associatedStreet.addMember(new RelationMember("street", street));
+                    associatedStreet.addMember(new RelationMember("street",
+                            street));
                 } else {
                     associatedStreet.put("name", streetName);
                 }
@@ -276,45 +414,72 @@
                     associatedStreet.addMember(new RelationMember("house", w));
                 }
                 this.commands.add(new AddCommand(associatedStreet));
-            }
-            else { // relation exists already - add new members
+            } else { // relation exists already - add new members
                 Relation newAssociatedStreet = new Relation(associatedStreet);
                 for (Way w : ways) {
-                    newAssociatedStreet.addMember(new RelationMember("house", w));
+                    newAssociatedStreet
+                            .addMember(new RelationMember("house", w));
                 }
-                this.commands.add(new ChangeCommand(associatedStreet, newAssociatedStreet));
+                this.commands.add(new ChangeCommand(associatedStreet,
+                        newAssociatedStreet));
             }
         }
+
+        // Remove the address node since their tags have been incorporated into
+        // the terraces.
+        // Or should removing them also be an option?
+        if (!housenumbers.isEmpty())
+            commands.add(DeleteCommand.delete(Main.main.getEditLayer(),
+                    housenumbers, true, true));
+
         Main.main.undoRedo.add(new SequenceCommand(tr("Terrace"), commands));
         if (nb > 1) {
             // Select the new building outlines (for quick reversing)
             Main.main.getCurrentDataSet().setSelected(ways);
         } else if (street != null) {
-            // Select the way (for quick selection of a new house (with the same way))
+            // Select the way (for quick selection of a new house (with the same
+            // way))
             Main.main.getCurrentDataSet().setSelected(street);
         }
     }
 
     /**
      * Adds address details to a single building
-     *
-     * @param outline The closed, quadrilateral way to add the address to.
-     * @param street The street, the buildings belong to (may be null)
-     * @param streetName the name of a street (may be null). Used if not null and street is null.
-     * @param number The house number
+     * 
+     * @param outline
+     *            The closed, quadrilateral way to add the address to.
+     * @param street
+     *            The street, the buildings belong to (may be null)
+     * @param streetName
+     *            the name of a street (may be null). Used if not null and
+     *            street is null.
+     * @param number
+     *            The house number
+     * @param additionalKeys
+     *            More keys to be copied onto the new outline
      * @return the way with added address details
      */
-    private Way addressBuilding(Way outline, Way street, String streetName, String number) {
+    private Way addressBuilding(Way outline, Way street, String streetName,
+            String number, Set<Entry<String, String>> additionalKeys) {
         Way changedOutline = outline;
         if (number != null) {
             // only, if the user has specified house numbers
-            this.commands.add(new ChangePropertyCommand(changedOutline, "addr:housenumber", number));
+            this.commands.add(new ChangePropertyCommand(changedOutline,
+                    "addr:housenumber", number));
         }
+        if (additionalKeys != null) {
+            for (Entry<String, String> entry : additionalKeys) {
+                this.commands.add(new ChangePropertyCommand(changedOutline,
+                        entry.getKey(), entry.getValue()));
+            }
+        }
         changedOutline.put("building", "yes");
         if (street != null) {
-            this.commands.add(new ChangePropertyCommand(changedOutline, "addr:street", street.get("name")));
+            this.commands.add(new ChangePropertyCommand(changedOutline,
+                    "addr:street", street.get("name")));
         } else if (streetName != null) {
-            this.commands.add(new ChangePropertyCommand(changedOutline, "addr:street", streetName));
+            this.commands.add(new ChangePropertyCommand(changedOutline,
+                    "addr:street", streetName));
         }
         return changedOutline;
     }
@@ -322,22 +487,29 @@
     /**
      * Creates a node at a certain distance along a way, as calculated by the
      * great circle distance.
-     *
+     * 
      * Note that this really isn't an efficient way to do this and leads to
-     * O(N^2) running time for the main algorithm, but its simple and easy
-     * to understand, and probably won't matter for reasonable-sized ways.
-     *
-     * @param w The way to interpolate.
-     * @param l The length at which to place the node.
+     * O(N^2) running time for the main algorithm, but its simple and easy to
+     * understand, and probably won't matter for reasonable-sized ways.
+     * 
+     * @param w
+     *            The way to interpolate.
+     * @param l
+     *            The length at which to place the node.
      * @return A node at a distance l along w from the first point.
      */
     private Node interpolateAlong(Way w, double l) {
-        List<Pair<Node,Node>> pairs = w.getNodePairs(false);
+        List<Pair<Node, Node>> pairs = w.getNodePairs(false);
         for (int i = 0; i < pairs.size(); ++i) {
-            Pair<Node,Node> p = pairs.get(i);
-            final double seg_length = p.a.getCoor().greatCircleDistance(p.b.getCoor());
-            if (l <= seg_length ||
-                    i == pairs.size() - 1) {    // be generous on the last segment (numerical roudoff can lead to a small overshoot)
+            Pair<Node, Node> p = pairs.get(i);
+            final double seg_length = p.a.getCoor().greatCircleDistance(
+                    p.b.getCoor());
+            if (l <= seg_length || i == pairs.size() - 1) { // be generous on
+                                                            // the last segment
+                                                            // (numerical
+                                                            // roudoff can lead
+                                                            // to a small
+                                                            // overshoot)
                 return interpolateNode(p.a, p.b, l / seg_length);
             } else {
                 l -= seg_length;
@@ -350,8 +522,9 @@
     /**
      * Calculates the great circle length of a way by summing the great circle
      * distance of each pair of nodes.
-     *
-     * @param w The way to calculate length of.
+     * 
+     * @param w
+     *            The way to calculate length of.
      * @return The length of the way.
      */
     private double wayLength(Way w) {
@@ -366,8 +539,9 @@
      * Given a way, try and find a definite front and back by looking at the
      * segments to find the "sides". Sides are assumed to be single segments
      * which cannot be contiguous.
-     *
-     * @param w The way to analyse.
+     * 
+     * @param w
+     *            The way to analyse.
      * @return A pair of ways (front, back) pointing in the same directions.
      */
     private Pair<Way, Way> findFrontAndBack(Way w) {
@@ -428,14 +602,15 @@
      * returns the distance of two segments of a closed polygon
      */
     private int indexDistance(int i1, int i2, int n) {
-        return Math.min(positiveModulus(i1 - i2, n), positiveModulus(i2 - i1, n));
+        return Math.min(positiveModulus(i1 - i2, n),
+                positiveModulus(i2 - i1, n));
     }
 
     /**
      * return the modulus in the range [0, n)
      */
     private int positiveModulus(int a, int n) {
-        if (n <=0)
+        if (n <= 0)
             throw new IllegalArgumentException();
         int res = a % n;
         if (res < 0) {
@@ -445,8 +620,8 @@
     }
 
     /**
-     * Calculate the length of a side (from node i to i+1) in a way. This assumes that
-     * the way is closed, but I only ever call it for buildings.
+     * Calculate the length of a side (from node i to i+1) in a way. This
+     * assumes that the way is closed, but I only ever call it for buildings.
      */
     private double sideLength(Way w, int i) {
         Node a = w.getNode(i);
@@ -456,15 +631,17 @@
 
     /**
      * Given an array of doubles (but this could made generic very easily) sort
-     * into order and return the array of indexes such that, for a returned array
-     * x, a[x[i]] is sorted for ascending index i.
-     *
-     * This isn't efficient at all, but should be fine for the small arrays we're
-     * expecting. If this gets slow - replace it with some more efficient algorithm.
-     *
-     * @param a The array to sort.
-     * @return An array of indexes, the same size as the input, such that a[x[i]]
-     * is in sorted order.
+     * into order and return the array of indexes such that, for a returned
+     * array x, a[x[i]] is sorted for ascending index i.
+     * 
+     * This isn't efficient at all, but should be fine for the small arrays
+     * we're expecting. If this gets slow - replace it with some more efficient
+     * algorithm.
+     * 
+     * @param a
+     *            The array to sort.
+     * @return An array of indexes, the same size as the input, such that
+     *         a[x[i]] is in sorted order.
      */
     private int[] sortedIndexes(final double[] a) {
         class SortWithIndex implements Comparable<SortWithIndex> {
@@ -517,8 +694,8 @@
 
     /**
      * Calculate sideness of a single segment given the nodes which make up that
-     * segment and its previous and next segments in order. Sideness is calculated
-     * for the segment b-c.
+     * segment and its previous and next segments in order. Sideness is
+     * calculated for the segment b-c.
      */
     private double calculateSideness(Node a, Node b, Node c, Node d) {
         final double ndx = b.getCoor().getX() - a.getCoor().getX();
@@ -533,10 +710,13 @@
     /**
      * Creates a new node at the interpolated position between the argument
      * nodes. Interpolates linearly in projected coordinates.
-     *
-     * @param a First node, at which f=0.
-     * @param b Last node, at which f=1.
-     * @param f Fractional position between first and last nodes.
+     * 
+     * @param a
+     *            First node, at which f=0.
+     * @param b
+     *            Last node, at which f=1.
+     * @param f
+     *            Fractional position between first and last nodes.
      * @return A new node at the interpolated position.
      */
     private Node interpolateNode(Node a, Node b, double f) {
Index: src/terracer/HouseNumberInputHandler.java
===================================================================
--- src/terracer/HouseNumberInputHandler.java	(revision 24695)
+++ src/terracer/HouseNumberInputHandler.java	(working copy)
@@ -18,85 +18,109 @@
 import java.awt.event.FocusListener;
 import java.awt.event.ItemEvent;
 import java.awt.event.ItemListener;
+import java.util.ArrayList;
 
 import javax.swing.JButton;
 import javax.swing.JTextField;
 import javax.swing.JOptionPane;
 
 import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.osm.Node;
 import org.openstreetmap.josm.data.osm.Way;
 import org.openstreetmap.josm.data.osm.Relation;
 import org.openstreetmap.josm.actions.JosmAction;
 
 /**
- * The Class HouseNumberInputHandler contains all the logic
- * behind the house number input dialog.
- *
- * From a refactoring viewpoint, this class is indeed more interested in the fields
- * of the HouseNumberInputDialog. This is desired design, as the HouseNumberInputDialog
- * is already cluttered with auto-generated layout code.
- *
+ * The Class HouseNumberInputHandler contains all the logic behind the house
+ * number input dialog.
+ * 
+ * From a refactoring viewpoint, this class is indeed more interested in the
+ * fields of the HouseNumberInputDialog. This is desired design, as the
+ * HouseNumberInputDialog is already cluttered with auto-generated layout code.
+ * 
  * @author casualwalker
  */
- public class HouseNumberInputHandler extends JosmAction implements ActionListener, FocusListener, ItemListener {
+public class HouseNumberInputHandler extends JosmAction implements
+        ActionListener, FocusListener, ItemListener {
     private TerracerAction terracerAction;
-    private Way outline, street;
+    private Way outline;
+    private Way street;
+    private String streetName;
     private Relation associatedStreet;
+    private ArrayList<Node> housenumbers;
     public HouseNumberInputDialog dialog;
 
     /**
      * Instantiates a new house number input handler.
-     *
-     * @param terracerAction the terracer action
-     * @param outline the closed, quadrilateral way to terrace.
-     * @param street the street, the buildings belong to (may be null)
-     * @param associatedStreet a relation where we can add the houses (may be null)
-     * @param title the title
+     * 
+     * @param terracerAction
+     *            the terracer action
+     * @param outline
+     *            the closed, quadrilateral way to terrace.
+     * @param street
+     *            the street, the buildings belong to (may be null)
+     * @param streetName
+     *            the name of the street, derived from either the street line or
+     *            the house numbers which are guaranteed to have the same name
+     *            attached (may be null)
+     * @param associatedStreet
+     *            a relation where we can add the houses (may be null)
+     * @param housenumbers
+     *            a list of house number nodes in this outline (may be empty)
+     * @param title
+     *            the title
      */
     public HouseNumberInputHandler(final TerracerAction terracerAction,
-            final Way outline, final Way street, final Relation associatedStreet,
-            final String title) {
+            final Way outline, final Way street, final String streetName,
+            final Relation associatedStreet,
+            final ArrayList<Node> housenumbers, final String title) {
         this.terracerAction = terracerAction;
         this.outline = outline;
         this.street = street;
+        this.streetName = streetName;
         this.associatedStreet = associatedStreet;
+        this.housenumbers = housenumbers;
 
         // This dialog is started modal
-        this.dialog = new HouseNumberInputDialog(this, street, associatedStreet != null);
+        this.dialog = new HouseNumberInputDialog(this, street, streetName,
+                associatedStreet != null, housenumbers);
 
         // We're done
     }
 
     /**
-     * Find a button with a certain caption.
-     * Loops recursively through all objects to find all buttons.
-     * Function returns on the first match.
-     *
-     * @param root A container object that is recursively searched for other containers or buttons
-     * @param caption The caption of the button that is being searched
-     *
+     * Find a button with a certain caption. Loops recursively through all
+     * objects to find all buttons. Function returns on the first match.
+     * 
+     * @param root
+     *            A container object that is recursively searched for other
+     *            containers or buttons
+     * @param caption
+     *            The caption of the button that is being searched
+     * 
      * @return The first button that matches the caption or null if not found
      */
     private static JButton getButton(Container root, String caption) {
         Component children[] = root.getComponents();
-         for (Component child : children) {
+        for (Component child : children) {
             JButton b;
             if (child instanceof JButton) {
                 b = (JButton) child;
-                if (caption.equals(b.getText())) return b;
+                if (caption.equals(b.getText()))
+                    return b;
             } else if (child instanceof Container) {
-                  b = getButton((Container)child, caption);
-                  if (b != null) return b;
-             }
-         }
+                b = getButton((Container) child, caption);
+                if (b != null)
+                    return b;
+            }
+        }
         return null;
     }
 
     /**
-     * Validate the current input fields.
-     * When the validation fails, a red message is
-     * displayed and the OK button is disabled.
-     *
+     * Validate the current input fields. When the validation fails, a red
+     * message is displayed and the OK button is disabled.
+     * 
      * Should be triggered each time the input changes.
      */
     private boolean validateInput() {
@@ -107,7 +131,8 @@
         isOk = isOk && checkSegmentsFromHousenumber(message);
         isOk = isOk && checkSegments(message);
 
-        // Allow non numeric characters for the low number as long as there is no high number of the segmentcount is 1
+        // Allow non numeric characters for the low number as long as there is
+        // no high number of the segmentcount is 1
         if (dialog.hi.getText().length() > 0 | segments() > 1) {
             isOk = isOk
                     && checkNumberStringField(dialog.lo, tr("Lowest number"),
@@ -127,36 +152,42 @@
 
             // For some reason the messageLabel doesn't want to show up
             dialog.messageLabel.setForeground(Color.black);
-            dialog.messageLabel.setText(tr(HouseNumberInputDialog.DEFAULT_MESSAGE));
+            dialog.messageLabel
+                    .setText(tr(HouseNumberInputDialog.DEFAULT_MESSAGE));
             return true;
         } else {
             JButton okButton = getButton(dialog, "OK");
             if (okButton != null)
                 okButton.setEnabled(false);
 
-            // For some reason the messageLabel doesn't want to show up, so a MessageDialog is shown instead. Someone more knowledgeable might fix this.
+            // For some reason the messageLabel doesn't want to show up, so a
+            // MessageDialog is shown instead. Someone more knowledgeable might
+            // fix this.
             dialog.messageLabel.setForeground(Color.red);
             dialog.messageLabel.setText(message.toString());
-            //JOptionPane.showMessageDialog(null, message.toString(), tr("Error"), JOptionPane.ERROR_MESSAGE);
+            // JOptionPane.showMessageDialog(null, message.toString(),
+            // tr("Error"), JOptionPane.ERROR_MESSAGE);
 
             return false;
         }
     }
 
     /**
-     * Checks, if the lowest house number is indeed lower than the
-     * highest house number.
-     * This check applies only, if the house number fields are used at all.
-     *
-     * @param message the message
-     *
+     * Checks, if the lowest house number is indeed lower than the highest house
+     * number. This check applies only, if the house number fields are used at
+     * all.
+     * 
+     * @param message
+     *            the message
+     * 
      * @return true, if successful
      */
     private boolean checkNumberOrder(final StringBuffer message) {
         if (numberFrom() != null && numberTo() != null) {
             if (numberFrom().intValue() > numberTo().intValue()) {
                 appendMessageNewLine(message);
-                message.append(tr("Lowest housenumber cannot be higher than highest housenumber"));
+                message
+                        .append(tr("Lowest housenumber cannot be higher than highest housenumber"));
                 return false;
             }
         }
@@ -164,45 +195,49 @@
     }
 
     /**
-     * Obtain the number segments from the house number fields and check,
-     * if they are valid.
-     *
-     * Also disables the segments field, if the house numbers contain
-     * valid information.
-     *
-     * @param message the message
-     *
+     * Obtain the number segments from the house number fields and check, if
+     * they are valid.
+     * 
+     * Also disables the segments field, if the house numbers contain valid
+     * information.
+     * 
+     * @param message
+     *            the message
+     * 
      * @return true, if successful
      */
     private boolean checkSegmentsFromHousenumber(final StringBuffer message) {
-        dialog.segments.setEditable(true);
+        if (!dialog.numbers.isVisible()) {
+            dialog.segments.setEditable(true);
 
-        if (numberFrom() != null && numberTo() != null) {
+            if (numberFrom() != null && numberTo() != null) {
 
-            int segments = numberTo().intValue() - numberFrom().intValue();
+                int segments = numberTo().intValue() - numberFrom().intValue();
 
-            if (segments % stepSize() != 0) {
-                appendMessageNewLine(message);
-                message.append(tr("Housenumbers do not match odd/even setting"));
-                return false;
-            }
+                if (segments % stepSize() != 0) {
+                    appendMessageNewLine(message);
+                    message
+                            .append(tr("Housenumbers do not match odd/even setting"));
+                    return false;
+                }
 
-            int steps = segments / stepSize();
-            steps++; // difference 0 means 1 building, see
-            // TerracerActon.terraceBuilding
-            dialog.segments.setText(String.valueOf(steps));
-            dialog.segments.setEditable(false);
+                int steps = segments / stepSize();
+                steps++; // difference 0 means 1 building, see
+                // TerracerActon.terraceBuilding
+                dialog.segments.setText(String.valueOf(steps));
+                dialog.segments.setEditable(false);
 
+            }
         }
         return true;
     }
 
     /**
-     * Check the number of segments.
-     * It must be a number and greater than 1.
-     *
-     * @param message the message
-     *
+     * Check the number of segments. It must be a number and greater than 1.
+     * 
+     * @param message
+     *            the message
+     * 
      * @return true, if successful
      */
     private boolean checkSegments(final StringBuffer message) {
@@ -217,11 +252,14 @@
 
     /**
      * Check, if a string field contains a positive integer.
-     *
-     * @param field the field
-     * @param label the label
-     * @param message the message
-     *
+     * 
+     * @param field
+     *            the field
+     * @param label
+     *            the label
+     * @param message
+     *            the message
+     * 
      * @return true, if successful
      */
     private boolean checkNumberStringField(final JTextField field,
@@ -247,8 +285,9 @@
 
     /**
      * Append a new line to the message, if the message is not empty.
-     *
-     * @param message the message
+     * 
+     * @param message
+     *            the message
      */
     private void appendMessageNewLine(final StringBuffer message) {
         if (message.length() > 0) {
@@ -256,16 +295,22 @@
         }
     }
 
-    /* (non-Javadoc)
-     * @see java.awt.event.ItemListener#itemStateChanged(java.awt.event.ItemEvent)
+    /*
+     * (non-Javadoc)
+     * 
+     * @see
+     * java.awt.event.ItemListener#itemStateChanged(java.awt.event.ItemEvent)
      * Called when the user selects from a pulldown selection
      */
     public void itemStateChanged(ItemEvent e) {
         validateInput();
     }
 
-    /* (non-Javadoc)
-     * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
+    /*
+     * (non-Javadoc)
+     * 
+     * @see
+     * java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
      */
     public void actionPerformed(final ActionEvent e) {
         // OK or Cancel button-actions
@@ -274,21 +319,22 @@
             if ("OK".equals(button.getActionCommand()) & button.isEnabled()) {
                 if (validateInput()) {
                     saveValues();
-
+		            
                     terracerAction.terraceBuilding(
-                        outline,
+	                    outline,
                         street,
                         associatedStreet,
                         segments(),
                         dialog.lo.getText(),
                         dialog.hi.getText(),
                         stepSize(),
+                        housenumbers,
                         streetName(),
                         doHandleRelation(),
                         doDeleteOutline());
-
+				
                     this.dialog.dispose();
-                }
+                    }
             } else if ("Cancel".equals(button.getActionCommand())) {
                 this.dialog.dispose();
             }
@@ -299,9 +345,9 @@
     }
 
     /**
-     * Calculate the step size between two house numbers,
-     * based on the interpolation setting.
-     *
+     * Calculate the step size between two house numbers, based on the
+     * interpolation setting.
+     * 
      * @return the stepSize (1 for all, 2 for odd /even)
      */
     public Integer stepSize() {
@@ -311,7 +357,7 @@
 
     /**
      * Gets the number of segments, if set.
-     *
+     * 
      * @return the number of segments or null, if not set / invalid.
      */
     public Integer segments() {
@@ -324,7 +370,7 @@
 
     /**
      * Gets the lowest house number.
-     *
+     * 
      * @return the number of lowest house number or null, if not set / invalid.
      */
     public Integer numberFrom() {
@@ -337,7 +383,7 @@
 
     /**
      * Gets the highest house number.
-     *
+     * 
      * @return the number of highest house number or null, if not set / invalid.
      */
     public Integer numberTo() {
@@ -350,12 +396,12 @@
 
     /**
      * Gets the street name.
-     *
-     * @return the  street name or null, if not set / invalid.
+     * 
+     * @return the street name or null, if not set / invalid.
      */
     public String streetName() {
-        if (street != null)
-            return null;
+        if (streetName != null)
+            return streetName;
 
         Object selected = dialog.streetComboBox.getSelectedItem();
         if (selected == null) {
@@ -371,22 +417,22 @@
     }
 
     /**
-     * Whether the user likes to create a relation or add to
-     * an existing one.
+     * Whether the user likes to create a relation or add to an existing one.
      */
     public boolean doHandleRelation() {
         if (this.dialog == null) {
-            JOptionPane.showMessageDialog(null, "dialog", "alert", JOptionPane.ERROR_MESSAGE);
+            JOptionPane.showMessageDialog(null, "dialog", "alert",
+                    JOptionPane.ERROR_MESSAGE);
         }
         if (this.dialog.handleRelationCheckBox == null) {
-            JOptionPane.showMessageDialog(null, "checkbox", "alert", JOptionPane.ERROR_MESSAGE);
+            JOptionPane.showMessageDialog(null, "checkbox", "alert",
+                    JOptionPane.ERROR_MESSAGE);
             return true;
-        }  else {
+        } else {
             return this.dialog.handleRelationCheckBox.isSelected();
         }
     }
 
-
     /**
      * Whether the user likes to delete the outline way.
      */
@@ -394,14 +440,18 @@
         return dialog.deleteOutlineCheckBox.isSelected();
     }
 
-    /* (non-Javadoc)
+    /*
+     * (non-Javadoc)
+     * 
      * @see java.awt.event.FocusListener#focusGained(java.awt.event.FocusEvent)
      */
     public void focusGained(FocusEvent e) {
         // Empty, but placeholder is required
     }
 
-    /* (non-Javadoc)
+    /*
+     * (non-Javadoc)
+     * 
      * @see java.awt.event.FocusListener#focusLost(java.awt.event.FocusEvent)
      */
     public void focusLost(FocusEvent e) {
@@ -415,8 +465,10 @@
      * Saves settings.
      */
     public void saveValues() {
-        Main.pref.put(HouseNumberInputDialog.HANDLE_RELATION, doHandleRelation());
+        Main.pref.put(HouseNumberInputDialog.HANDLE_RELATION,
+                doHandleRelation());
         Main.pref.put(HouseNumberInputDialog.DELETE_OUTLINE, doDeleteOutline());
-        Main.pref.put(HouseNumberInputDialog.INTERPOLATION, stepSize().toString());
+        Main.pref.put(HouseNumberInputDialog.INTERPOLATION, stepSize()
+                .toString());
     }
 }
