Index: applications/editors/josm/plugins/CustomizePublicTransportStop/build.xml
===================================================================
--- applications/editors/josm/plugins/CustomizePublicTransportStop/build.xml	(revision 34500)
+++ applications/editors/josm/plugins/CustomizePublicTransportStop/build.xml	(revision 34501)
@@ -28,5 +28,5 @@
             <manifest>
                 <attribute name="Author" value="Rodion Scherbakov"/>
-                <attribute name="Plugin-Class" value="ru.rodsoft.openstreetmap.josm.plugins.customizepublictransportstop.CustomizePublicTransportStopPlugin"/>
+                <attribute name="Plugin-Class" value="org.openstreetmap.josm.plugins.customizepublictransportstop.CustomizePublicTransportStopPlugin"/>
                 <attribute name="Plugin-Date" value="${version.entry.commit.date}"/>
                 <attribute name="Plugin-Description" value="Customization of public public transport stops."/>
Index: applications/editors/josm/plugins/CustomizePublicTransportStop/src/org/openstreetmap/josm/plugins/customizepublictransportstop/CreateNewStopPointOperation.java
===================================================================
--- applications/editors/josm/plugins/CustomizePublicTransportStop/src/org/openstreetmap/josm/plugins/customizepublictransportstop/CreateNewStopPointOperation.java	(revision 34501)
+++ applications/editors/josm/plugins/CustomizePublicTransportStop/src/org/openstreetmap/josm/plugins/customizepublictransportstop/CreateNewStopPointOperation.java	(revision 34501)
@@ -0,0 +1,337 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.customizepublictransportstop;
+
+import java.awt.Point;
+import java.awt.geom.Point2D;
+import java.util.AbstractMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.openstreetmap.josm.command.AddCommand;
+import org.openstreetmap.josm.command.ChangeCommand;
+import org.openstreetmap.josm.data.UndoRedoHandler;
+import org.openstreetmap.josm.data.coor.EastNorth;
+import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.osm.BBox;
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.data.osm.WaySegment;
+import org.openstreetmap.josm.data.projection.ProjectionRegistry;
+import org.openstreetmap.josm.gui.MainApplication;
+import org.openstreetmap.josm.gui.MapView;
+import org.openstreetmap.josm.spi.preferences.Config;
+import org.openstreetmap.josm.tools.Geometry;
+
+/**
+ * Operation of creation of new stop point
+ * 
+ * @author Rodion Scherbakov
+ */
+public class CreateNewStopPointOperation extends StopAreaOperationBase {
+
+    /**
+     * Constructor of operation object
+     * 
+     * @param currentDataSet Current Josm data set
+     */
+    public CreateNewStopPointOperation(DataSet currentDataSet) {
+        super(currentDataSet);
+    }
+
+    /**
+     * The *result* does not depend on the current map selection state, neither does
+     * the result *order*. It solely depends on the distance to point p.
+     *
+     * This code is coped from JOSM code
+     * 
+     * @return a sorted map with the keys representing the distance of their
+     *         associated nodes to point p.
+     */
+    private Map<Double, List<Node>> getNearestNodesImpl(Point p) {
+        TreeMap<Double, List<Node>> nearestMap = new TreeMap<>();
+        DataSet ds = getCurrentDataSet();
+
+        if (ds != null) {
+            double dist, snapDistanceSq = 200;
+            snapDistanceSq *= snapDistanceSq;
+
+            for (Node n : ds.searchNodes(getBBox(p, 200))) {
+                if ((dist = MainApplication.getMap().mapView.getPoint2D(n).distanceSq(p)) < snapDistanceSq) {
+                    List<Node> nlist;
+                    if (nearestMap.containsKey(dist)) {
+                        nlist = nearestMap.get(dist);
+                    } else {
+                        nlist = new LinkedList<>();
+                        nearestMap.put(dist, nlist);
+                    }
+                    nlist.add(n);
+                }
+            }
+        }
+
+        return nearestMap;
+    }
+
+    /**
+     * Selection of area for search of roads
+     * 
+     * @param p Current point
+     * @param snapDistance Distance for search
+     * @return Area
+     */
+    private BBox getBBox(Point p, int snapDistance) {
+        MapView mapView = MainApplication.getMap().mapView;
+        return new BBox(mapView.getLatLon(p.x - snapDistance, p.y - snapDistance),
+                mapView.getLatLon(p.x + snapDistance, p.y + snapDistance));
+    }
+
+    /**
+     * Search of nearest points on ways
+     * 
+     * @param platformCoord Platform coordinates
+     * @param stopArea Stop area object
+     * @return Dictionary of founded points and distances from platform
+     */
+    public AbstractMap.SimpleEntry<Double, Node> getNearestNode(LatLon platformCoord, StopArea stopArea) {
+        Point p = MainApplication.getMap().mapView.getPoint(platformCoord);
+        Map<Double, List<Node>> dist_nodes = getNearestNodesImpl(p);
+        Double[] distances = dist_nodes.keySet().toArray(new Double[0]);
+        distances = sort(distances);
+        Integer distanceIndex = -1;
+        Node nearestNode = null;
+        while (++distanceIndex < distances.length && nearestNode == null) {
+            List<Node> nodes = dist_nodes.get(distances[distanceIndex]);
+            for (Node node : nodes) {
+                for (Way way : getCurrentDataSet().getWays()) {
+                    if (way.getNodes().contains(node) && testWay(way, stopArea)) {
+                        nearestNode = node;
+                        return new AbstractMap.SimpleEntry<Double, Node>(distances[distanceIndex], nearestNode);
+                    }
+                }
+                if (nearestNode != null)
+                    break;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Sorting of founded points by distance
+     * 
+     * @param distances Array of distances
+     * @return Sorted array of distances
+     */
+    public Double[] sort(Double[] distances) {
+        for (Integer i = 0; i < distances.length - 1; i++) {
+            for (Integer j = i + 1; j < distances.length; j++) {
+                if (distances[i] > distances[j]) {
+                    Double d = distances[i];
+                    distances[i] = distances[j];
+                    distances[j] = d;
+                }
+            }
+        }
+        return distances;
+    }
+
+    /**
+     * Selection of ways for stop position by type of way and type of stop
+     * 
+     * @param way The way
+     * @param stopArea Stop area
+     * @return true, if way can contain stop position
+     */
+    public Boolean testWay(Way way, StopArea stopArea) {
+        if (stopArea.isTrainStation || stopArea.isTrainStop) {
+            if (OSMTags.RAIL_TAG_VALUE.equals(way.getKeys().get(OSMTags.RAILWAY_TAG))
+                    && OSMTags.MAIN_TAG_VALUE.equals(way.getKeys().get(OSMTags.USAGE_TAG)))
+                return true;
+            return false;
+        }
+
+        if (stopArea.isTram) {
+            if (OSMTags.TRAM_TAG_VALUE.equals(way.getKeys().get(OSMTags.RAILWAY_TAG)))
+                return true;
+            return false;
+        }
+
+        String[] highwayValues = {OSMTags.TRUNK_TAG_VALUE, OSMTags.PRIMARY_TAG_VALUE, OSMTags.SECONDARY_TAG_VALUE,
+                OSMTags.TERTIARY_TAG_VALUE, OSMTags.UNCLASSIFIED_TAG_VALUE, OSMTags.RESIDENTIAL_TAG_VALUE,
+                OSMTags.SERVICE_TAG_VALUE, OSMTags.BUS_GUIDEWAY_TAG_VALUE, OSMTags.ROAD_TAG_VALUE,
+                OSMTags.TRUNK_LINK_TAG_VALUE, OSMTags.PRIMARY_LINK_TAG_VALUE, OSMTags.SECONDARY_LINK_TAG_VALUE,
+                OSMTags.TERTIARY_LINK_TAG_VALUE};
+        if (stopArea.isBus || stopArea.isTrolleybus || stopArea.isShareTaxi) {
+            String highway = way.getKeys().get(OSMTags.HIGHWAY_TAG);
+            if (highway != null)
+                for (Integer i = 0; i < highwayValues.length; i++) {
+                    if (highwayValues[i].equals(highway))
+                        return true;
+                }
+        }
+        return false;
+    }
+
+    /**
+     * The *result* does not depend on the current map selection state, neither does
+     * the result *order*. It solely depends on the distance to point p.
+     *
+     * This code is coped from JOSM code
+     * 
+     * @return a sorted map with the keys representing the perpendicular distance of
+     *         their associated way segments to point p.
+     */
+    private Map<Double, List<WaySegment>> getNearestWaySegmentsImpl(Point p) {
+        Map<Double, List<WaySegment>> nearestMap = new TreeMap<>();
+        DataSet ds = getCurrentDataSet();
+
+        if (ds != null) {
+            double snapDistanceSq = Config.getPref().getInt("mappaint.segment.snap-distance", 200);
+            snapDistanceSq *= snapDistanceSq;
+
+            for (Way w : ds.searchWays(getBBox(p, Config.getPref().getInt("mappaint.segment.snap-distance", 200)))) {
+                Node lastN = null;
+                int i = -2;
+                for (Node n : w.getNodes()) {
+                    i++;
+                    if (n.isDeleted() || n.isIncomplete()) { // FIXME: This shouldn't happen, raise exception?
+                        continue;
+                    }
+                    if (lastN == null) {
+                        lastN = n;
+                        continue;
+                    }
+
+                    Point2D A = MainApplication.getMap().mapView.getPoint2D(lastN);
+                    Point2D B = MainApplication.getMap().mapView.getPoint2D(n);
+                    double c = A.distanceSq(B);
+                    double a = p.distanceSq(B);
+                    double b = p.distanceSq(A);
+
+                    /*
+                     * perpendicular distance squared loose some precision to account for possible
+                     * deviations in the calculation above e.g. if identical (A and B) come about
+                     * reversed in another way, values may differ -- zero out least significant 32
+                     * dual digits of mantissa..
+                     */
+                    double perDistSq = Double.longBitsToDouble(
+                            // resolution in numbers with large exponent not needed here..
+                            Double.doubleToLongBits(a - (a - b + c) * (a - b + c) / 4 / c) >> 32 << 32);
+
+                    if (perDistSq < snapDistanceSq && a < c + snapDistanceSq && b < c + snapDistanceSq) {
+                        List<WaySegment> wslist;
+                        if (nearestMap.containsKey(perDistSq)) {
+                            wslist = nearestMap.get(perDistSq);
+                        } else {
+                            wslist = new LinkedList<>();
+                            nearestMap.put(perDistSq, wslist);
+                        }
+                        wslist.add(new WaySegment(w, i));
+                    }
+
+                    lastN = n;
+                }
+            }
+        }
+
+        return nearestMap;
+    }
+
+    /**
+     * Selection of nearest way for stop position
+     * 
+     * @param platformCoord Platform coordinates
+     * @param stopArea Stop area
+     * @return Nearest way segment
+     */
+    protected NearestWaySegment getNearestWaySegment(LatLon platformCoord, StopArea stopArea) {
+        MapView mapView = MainApplication.getMap().mapView;
+        Point p = mapView.getPoint(platformCoord);
+        Map<Double, List<WaySegment>> dist_waySegments = getNearestWaySegmentsImpl(p);
+        for (Map.Entry<Double, List<WaySegment>> entry : dist_waySegments.entrySet()) {
+            for (WaySegment waySegment : entry.getValue()) {
+                if (testWay(waySegment.way, stopArea)) {
+                    Node n = waySegment.getFirstNode();
+                    Node lastN = waySegment.getSecondNode();
+
+                    EastNorth newPosition = Geometry.closestPointToSegment(n.getEastNorth(), lastN.getEastNorth(),
+                            ProjectionRegistry.getProjection().latlon2eastNorth(platformCoord));
+                    LatLon newNodePosition = ProjectionRegistry.getProjection().eastNorth2latlon(newPosition);
+                    Point2D lastN2D = mapView.getPoint2D(lastN);
+                    Point2D n2D = mapView.getPoint2D(n);
+                    Point2D newNodePosition2D = mapView.getPoint2D(newNodePosition);
+                    Double distCurrenNodes = lastN2D.distance(n2D);
+                    if ((newNodePosition2D.distance(lastN2D) < distCurrenNodes)
+                            && (newNodePosition2D.distance(n2D) < distCurrenNodes)) {
+                        return new NearestWaySegment(entry.getKey(), waySegment, new Node(newNodePosition));
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Creation of stop position node on nearest way
+     * 
+     * @param newStopNode New stop position node
+     * @param waySegment Way segment including stop position node
+     * @return Stop position node
+     */
+    protected Node createNodeOnWay(Node newStopNode, WaySegment waySegment) {
+        UndoRedoHandler.getInstance().add(new AddCommand(MainApplication.getLayerManager().getEditDataSet(), newStopNode));
+        List<Node> wayNodes = waySegment.way.getNodes();
+        wayNodes.add(waySegment.lowerIndex + 1, newStopNode);
+        Way newWay = new Way(waySegment.way);
+        newWay.setNodes(wayNodes);
+        UndoRedoHandler.getInstance().add(new ChangeCommand(waySegment.way, newWay));
+        return newStopNode;
+    }
+
+    /**
+     * Creation of stop position
+     * 
+     * @param stopArea Stop Area
+     */
+    @Override
+    public StopArea performCustomizing(StopArea stopArea) {
+        LatLon platformCoord = null;
+        if (stopArea.selectedObject instanceof Node) {
+            platformCoord = ((Node) stopArea.selectedObject).getCoor();
+        } else
+            platformCoord = getCenterOfWay(stopArea.selectedObject);
+        if (platformCoord == null)
+            return stopArea;
+        AbstractMap.SimpleEntry<Double, Node> nearestNode = getNearestNode(platformCoord, stopArea);
+        NearestWaySegment nearestWaySegment = getNearestWaySegment(platformCoord, stopArea);
+        Node newStopPointNode = null;
+        if (nearestNode != null && nearestWaySegment != null) {
+            MapView mapView = MainApplication.getMap().mapView;
+            Double segmentDist = mapView.getPoint2D(platformCoord)
+                    .distanceSq(mapView.getPoint2D(nearestWaySegment.newNode));
+            Double nodeDistSq = nearestNode.getKey();
+            // nodeDistSq *= nodeDistSq - 2;
+            if (segmentDist < nodeDistSq - 2) {
+                // MessageBox.ok("new stop node v2 " + segmentDist.toString() + " " +
+                // nodeDistSq.toString());
+                newStopPointNode = createNodeOnWay(nearestWaySegment.newNode, nearestWaySegment.waySegment);
+            } else {
+                // MessageBox.ok("new stop node v3 " + segmentDist.toString() + " " +
+                // nodeDistSq.toString());
+                newStopPointNode = nearestNode.getValue();
+            }
+        } else if (nearestNode != null && nearestWaySegment == null) {
+            newStopPointNode = nearestNode.getValue();
+        } else if (nearestNode == null && nearestWaySegment != null) {
+            // MessageBox.ok("new stop node2");
+            newStopPointNode = createNodeOnWay(nearestWaySegment.newNode, nearestWaySegment.waySegment);
+        }
+        if (newStopPointNode != null) {
+            stopArea.stopPoints.add(newStopPointNode);
+        }
+        return stopArea;
+    }
+
+}
Index: applications/editors/josm/plugins/CustomizePublicTransportStop/src/org/openstreetmap/josm/plugins/customizepublictransportstop/CreateStopAreaFromSelectedObjectOperation.java
===================================================================
--- applications/editors/josm/plugins/CustomizePublicTransportStop/src/org/openstreetmap/josm/plugins/customizepublictransportstop/CreateStopAreaFromSelectedObjectOperation.java	(revision 34501)
+++ applications/editors/josm/plugins/CustomizePublicTransportStop/src/org/openstreetmap/josm/plugins/customizepublictransportstop/CreateStopAreaFromSelectedObjectOperation.java	(revision 34501)
@@ -0,0 +1,167 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.customizepublictransportstop;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+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;
+
+/**
+ * Operation of constructing of stop area object from selected JOSM object
+ * 
+ * @author Rodion Scherbakov
+ */
+public class CreateStopAreaFromSelectedObjectOperation extends StopAreaOperationBase {
+
+    /**
+     * Constructor of operation object
+     * 
+     * @param currentDataSet Current Josm data set
+     */
+    public CreateStopAreaFromSelectedObjectOperation(DataSet currentDataSet) {
+        super(currentDataSet);
+    }
+
+    /**
+     * Parsing of josm object tags and customizing of stop area object
+     * 
+     * @param member Josm object
+     */
+    public void parseTags(StopArea stopArea, OsmPrimitive member) {
+        if (stopArea.name == null)
+            stopArea.name = getTagValue(member, OSMTags.NAME_TAG);
+        if (stopArea.nameEn == null)
+            stopArea.nameEn = getTagValue(member, OSMTags.NAME_EN_TAG);
+        if (stopArea.operator == null)
+            stopArea.operator = getTagValue(member, OSMTags.OPERATOR_TAG);
+        if (stopArea.network == null)
+            stopArea.network = getTagValue(member, OSMTags.NETWORK_TAG);
+        if (stopArea.service == null)
+            stopArea.service = getTagValue(member, OSMTags.SERVICE_TAG);
+        if (OSMTags.LOCAL_NETWORK_TAG_VALUE.equals(stopArea.service))
+            stopArea.service = OSMTags.COMMUTER_NETWORK_TAG_VALUE;
+        if (compareTag(member, OSMTags.BUS_TAG, OSMTags.YES_TAG_VALUE))
+            stopArea.isBus = true;
+        if (compareTag(member, OSMTags.TROLLEYBUS_TAG, OSMTags.YES_TAG_VALUE))
+            stopArea.isTrolleybus = true;
+        if (compareTag(member, OSMTags.SHARE_TAXI_TAG, OSMTags.YES_TAG_VALUE))
+            stopArea.isShareTaxi = true;
+        if (!(stopArea.isBus || stopArea.isShareTaxi || stopArea.isTrolleybus)
+                && compareTag(member, OSMTags.HIGHWAY_TAG, OSMTags.BUS_STOP_TAG_VALUE))
+            stopArea.isBus = true;
+        if (compareTag(member, OSMTags.TRAM_TAG, OSMTags.YES_TAG_VALUE)
+                || compareTag(member, OSMTags.RAILWAY_TAG, OSMTags.TRAM_STOP_TAG_VALUE))
+            stopArea.isTram = true;
+        if (compareTag(member, OSMTags.RAILWAY_TAG, OSMTags.HALT_TAG_VALUE))
+            stopArea.isTrainStop = true;
+        if (compareTag(member, OSMTags.RAILWAY_TAG, OSMTags.STATION_TAG_VALUE))
+            stopArea.isTrainStation = true;
+        if (compareTag(member, OSMTags.AMENITY_TAG, OSMTags.BUS_STATION_TAG_VALUE)) {
+            stopArea.isBusStation = true;
+        }
+        if (member == stopArea.selectedObject) {
+            if (compareTag(member, OSMTags.BENCH_TAG, OSMTags.YES_TAG_VALUE))
+                stopArea.isBench = true;
+            if (compareTag(member, OSMTags.SHELTER_TAG, OSMTags.YES_TAG_VALUE))
+                stopArea.isShelter = true;
+            if (compareTag(member, OSMTags.COVERED_TAG, OSMTags.YES_TAG_VALUE))
+                stopArea.isCovered = true;
+            if (compareTag(member, OSMTags.AREA_TAG, OSMTags.YES_TAG_VALUE))
+                stopArea.isArea = true;
+        }
+    }
+
+    /**
+     * Test, are transport types assigned to platforms
+     * 
+     * @param platform Platform object
+     * @return true, if transport types assigned to this platforms
+     */
+    public boolean testIsTransportTypeAssigned(OsmPrimitive platform) {
+        String[] transportTypes = new String[] {OSMTags.BUS_TAG, OSMTags.TROLLEYBUS_TAG, OSMTags.SHARE_TAXI_TAG,
+                OSMTags.TRAM_TAG, OSMTags.TRAIN_TAG};
+        for (String transportType : transportTypes) {
+            if (compareTag(platform, transportType, OSMTags.YES_TAG_VALUE))
+                return true;
+        }
+        return false;
+    }
+
+    /**
+     * Setting of stop area from selected josm object
+     * 
+     * @param selectedObject Selected josm object
+     */
+    public void fromSelectedObject(StopArea stopArea) {
+        Collection<OsmPrimitive> selectedObjects = new ArrayList<OsmPrimitive>();
+        selectedObjects.add(stopArea.selectedObject);
+        for (Relation rel : OsmPrimitive.getParentRelations(selectedObjects)) {
+            if (compareTag(rel, OSMTags.TYPE_TAG, OSMTags.PUBLIC_TRANSPORT_TAG)
+                    && compareTag(rel, OSMTags.PUBLIC_TRANSPORT_TAG, OSMTags.STOP_AREA_TAG_VALUE)) {
+                stopArea.stopAreaRelation = rel;
+            }
+            if (stopArea.stopAreaRelation != null)
+                break;
+        }
+
+        if (stopArea.stopAreaRelation != null) {
+            parseTags(stopArea, stopArea.stopAreaRelation);
+            parseTags(stopArea, stopArea.selectedObject);
+            for (RelationMember member : stopArea.stopAreaRelation.getMembers()) {
+                if (member.getMember() instanceof Node && compareTag(member.getMember(), OSMTags.PUBLIC_TRANSPORT_TAG,
+                        OSMTags.STOP_POSITION_TAG_VALUE)) {
+                    stopArea.isStopPointExists = true;
+                    stopArea.stopPoints.add(member.getNode());
+                } else if (compareTag(member.getMember(), OSMTags.PUBLIC_TRANSPORT_TAG, OSMTags.PLATFORM_TAG_VALUE)) {
+                    stopArea.platforms.add(member.getMember());
+                } else {
+                    stopArea.otherMembers.add(member.getMember());
+                }
+                parseTags(stopArea, member.getMember());
+            }
+            if (!stopArea.platforms.contains(stopArea.selectedObject)) {
+                parseTags(stopArea, stopArea.selectedObject);
+                stopArea.platforms.add(stopArea.selectedObject);
+            }
+        } else {
+            parseTags(stopArea, stopArea.selectedObject);
+            stopArea.platforms.add(stopArea.selectedObject);
+        }
+        for (OsmPrimitive platform : stopArea.platforms) {
+            if (testIsTransportTypeAssigned(platform)) {
+                stopArea.isAssignTransportType = true;
+                break;
+            }
+        }
+        if (!(stopArea.isBus || stopArea.isTrolleybus || stopArea.isShareTaxi) && stopArea.selectedObject != null
+                && (compareTag(stopArea.selectedObject, OSMTags.HIGHWAY_TAG, OSMTags.BUS_STOP_TAG_VALUE)
+                        || stopArea.isBusStation)) {
+            stopArea.isBus = true;
+        }
+    }
+
+    /**
+     * Construct stop area object from selected JOSM object
+     * 
+     * @param stopArea Original stop area object
+     * @return Stop area objects with settings of selected JOSM object and included
+     *         it stop area relation
+     */
+    @Override
+    public StopArea performCustomizing(StopArea stopArea) {
+        if (getCurrentDataSet() == null)
+            return null;
+        OsmPrimitive selectedObject = getCurrentDataSet().getSelectedNodesAndWays().iterator().next();
+        if (selectedObject == null)
+            return null;
+        if (stopArea == null)
+            stopArea = new StopArea(selectedObject);
+        fromSelectedObject(stopArea);
+        return stopArea;
+    }
+
+}
Index: applications/editors/josm/plugins/CustomizePublicTransportStop/src/org/openstreetmap/josm/plugins/customizepublictransportstop/CustomizePublicTransportStopDialog.java
===================================================================
--- applications/editors/josm/plugins/CustomizePublicTransportStop/src/org/openstreetmap/josm/plugins/customizepublictransportstop/CustomizePublicTransportStopDialog.java	(revision 34501)
+++ applications/editors/josm/plugins/CustomizePublicTransportStop/src/org/openstreetmap/josm/plugins/customizepublictransportstop/CustomizePublicTransportStopDialog.java	(revision 34501)
@@ -0,0 +1,600 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.customizepublictransportstop;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.Frame;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.util.HashMap;
+
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+
+import org.openstreetmap.josm.gui.MainApplication;
+
+/**
+ * Dialog for setting stop area properties
+ * 
+ * @author Rodion Scherbakov
+ */
+public class CustomizePublicTransportStopDialog implements ActionListener, ItemListener {
+    private static final String CANCEL_COMMAND = "cancel";
+    private static final String SAVE_COMMAND = "save";
+    private static final String CANCEL_BUTTON_CAPTION = "Cancel";
+    private static final String SAVE_BUTTON_CAPTION = "Save";
+    private static final String AREA_CAPTION = "Area";
+    private static final String COVER_CAPTION = "Cover";
+    private static final String SHELDER_CAPTION = "Shelder";
+    private static final String BENCH_CAPTION = "Bench";
+    private static final String RAILWAY_STOP_CAPTION = "Railway stop";
+    private static final String RAILWAY_STATION_CAPTION = "Railway station";
+    private static final String TRAM_CAPTION = "Tram";
+    private static final String TROLLEYBUS_CAPTION = "Trolleybus";
+    private static final String SHARE_TAXI_CAPTION = "Share taxi";
+    private static final String BUS_CAPTION = "Bus";
+    private static final String BUS_STATION_CAPTION = "Bus station";
+    private static final String ASSIGN_TRANSPORT_TYPE_CAPTION = "Assign transport type to platform";
+    private static final String NETWORK_LEVEL_CAPTION = "Network level";
+    private static final String OPERATOR_CAPTION = "Operator";
+    private static final String NETWORK_CAPTION = "Network";
+    private static final String NAME_EN_CAPTION = "Name (en.)";
+    private static final String NAME_CAPTION = "Name";
+    private static final String STOP_CUSTOMIZING_DIALOG_CAPTION = "Stop customizing";
+    public static final String LONG_DISTANCE_NETWORK_CAPTION = "Long distance";
+    public static final String REGIONAL_NETWORK_CAPTION = "Regional";
+    public static final String COMMUTER_NETWORK_CAPTION = "Commuter";
+    public static final String CITY_NETWORK_CAPTION = "City transport";
+    public static final String HIGH_SPEED_NETWORK_CAPTION = "High speed";
+
+    private String[] serviceCaptionStrings = {CITY_NETWORK_CAPTION, COMMUTER_NETWORK_CAPTION, REGIONAL_NETWORK_CAPTION,
+            LONG_DISTANCE_NETWORK_CAPTION, HIGH_SPEED_NETWORK_CAPTION};
+    private String[] serviceStrings = {OSMTags.CITY_NETWORK_TAG_VALUE, OSMTags.COMMUTER_NETWORK_TAG_VALUE,
+            OSMTags.REGIONAL_NETWORK_TAG_VALUE, OSMTags.LONG_DISTANCE_NETWORK_TAG_VALUE,
+            OSMTags.HIGH_SPEED_NETWORK_TAG_VALUE};
+
+    private JDialog jDialog = null;
+    private JTextField textFieldName = null;
+    private JTextField textFieldNameEn;
+    private JTextField textFieldNetwork;
+    private JTextField textFieldOperator;
+    private JComboBox<String> comboBoxService;
+    private JCheckBox checkBoxIsBus;
+    private JCheckBox checkBoxIsTrolleybus;
+    private JCheckBox checkBoxIsShareTaxi;
+    private JCheckBox checkBoxIsBusStation;
+    private JCheckBox checkBoxIsAssignTransportType;
+    private JCheckBox checkBoxIsTram;
+    private JCheckBox checkBoxIsTrainStation;
+    private JCheckBox checkBoxIsTrainStop;
+    private JCheckBox checkBoxIsBench;
+    private JCheckBox checkBoxIsShelder;
+    private JCheckBox checkBoxIsCover;
+    private JCheckBox checkBoxIsArea;
+
+    /**
+     * Stop area
+     */
+    private StopArea stopArea;
+    /**
+     * Customize stop action object for callback
+     */
+    private CustomizeStopAction customizeStopAction;
+
+    /**
+     * Map of check boxes
+     */
+    private HashMap<JCheckBox, Boolean> checkBoxValues = new HashMap<JCheckBox, Boolean>();
+
+    /**
+     * Previous stop name
+     */
+    private static String previousName;
+    /**
+     * Previous english stop name
+     */
+    private static String previousNameEn;
+    /**
+     * Network name at previous call
+     */
+    private static String previousNetwork = null;
+    /**
+     * Operator name at previous call
+     */
+    private static String previousOperator = null;
+
+    /**
+     * Reference to dialog object
+     */
+    private static CustomizePublicTransportStopDialog customizePublicTransportStopDialogInstance;
+
+    /**
+     * Construct dialog and fill controls
+     * 
+     * @param customizeStopAction Stop area customizing action
+     * @param stopArea Stop area
+     * @return Reference to dialog
+     */
+    public static CustomizePublicTransportStopDialog showCustomizePublicTransportStopDialog(
+            CustomizeStopAction customizeStopAction, StopArea stopArea) {
+        if (customizePublicTransportStopDialogInstance == null) {
+            customizePublicTransportStopDialogInstance = new CustomizePublicTransportStopDialog(customizeStopAction,
+                    stopArea);
+        } else {
+            customizePublicTransportStopDialogInstance.setCustomizeStopAction(customizeStopAction);
+            customizePublicTransportStopDialogInstance.setStopArea(stopArea);
+        }
+        customizePublicTransportStopDialogInstance.setVisible(true);
+        return customizePublicTransportStopDialogInstance;
+    }
+
+    /**
+     * Constructor of dialog
+     */
+    public CustomizePublicTransportStopDialog() {
+        Frame frame = JOptionPane.getFrameForComponent(MainApplication.getMainFrame());
+        jDialog = new JDialog(frame, tr(STOP_CUSTOMIZING_DIALOG_CAPTION), false);
+        JPanel contentPane = createContentPane();
+
+        jDialog.add(contentPane);
+
+        jDialog.pack();
+        jDialog.setLocationRelativeTo(frame);
+    }
+
+    private JPanel createContentPane() {
+        JPanel contentPane = new JPanel();
+        GridBagLayout gridbag = new GridBagLayout();
+        contentPane.setLayout(gridbag);
+        GridBagConstraints layoutCons = new GridBagConstraints();
+        JLabel label = new JLabel(tr(NAME_CAPTION));
+        layoutCons.gridx = 0;
+        layoutCons.gridy = 0;
+        layoutCons.weightx = 0.5;
+        layoutCons.fill = GridBagConstraints.HORIZONTAL;
+        gridbag.setConstraints(label, layoutCons);
+        contentPane.add(label);
+
+        textFieldName = new JTextField("", 25);
+        layoutCons.gridx = 1;
+        layoutCons.gridy = 0;
+        layoutCons.weightx = 0.5;
+        layoutCons.fill = GridBagConstraints.HORIZONTAL;
+        gridbag.setConstraints(textFieldName, layoutCons);
+        contentPane.add(textFieldName);
+
+        JLabel labelNameEn = new JLabel(tr(NAME_EN_CAPTION));
+        layoutCons.gridx = 0;
+        layoutCons.gridy = 1;
+        layoutCons.weightx = 0.5;
+        layoutCons.fill = GridBagConstraints.HORIZONTAL;
+        gridbag.setConstraints(labelNameEn, layoutCons);
+        contentPane.add(labelNameEn);
+
+        textFieldNameEn = new JTextField("", 25);
+        layoutCons.gridx = 1;
+        layoutCons.gridy = 1;
+        layoutCons.weightx = 0.5;
+        layoutCons.fill = GridBagConstraints.HORIZONTAL;
+        gridbag.setConstraints(textFieldNameEn, layoutCons);
+        contentPane.add(textFieldNameEn);
+
+        JLabel labelNetwork = new JLabel(tr(NETWORK_CAPTION));
+        layoutCons.gridx = 0;
+        layoutCons.gridy = 2;
+        layoutCons.weightx = 0.5;
+        layoutCons.fill = GridBagConstraints.HORIZONTAL;
+        gridbag.setConstraints(labelNetwork, layoutCons);
+        contentPane.add(labelNetwork);
+
+        textFieldNetwork = new JTextField("", 25);
+        layoutCons.gridx = 1;
+        layoutCons.gridy = 2;
+        layoutCons.weightx = 0.5;
+        layoutCons.fill = GridBagConstraints.HORIZONTAL;
+        gridbag.setConstraints(textFieldNetwork, layoutCons);
+        contentPane.add(textFieldNetwork);
+
+        JLabel labelOperator = new JLabel(tr(OPERATOR_CAPTION));
+        layoutCons.gridx = 0;
+        layoutCons.gridy = 3;
+        layoutCons.weightx = 0.5;
+        layoutCons.fill = GridBagConstraints.HORIZONTAL;
+        gridbag.setConstraints(labelOperator, layoutCons);
+        contentPane.add(labelOperator);
+
+        textFieldOperator = new JTextField("", 25);
+        layoutCons.gridx = 1;
+        layoutCons.gridy = 3;
+        layoutCons.weightx = 0.5;
+        layoutCons.fill = GridBagConstraints.HORIZONTAL;
+        gridbag.setConstraints(textFieldOperator, layoutCons);
+        contentPane.add(textFieldOperator);
+
+        JLabel labelService = new JLabel(tr(NETWORK_LEVEL_CAPTION));
+        layoutCons.gridx = 0;
+        layoutCons.gridy = 4;
+        layoutCons.weightx = 0.5;
+        layoutCons.fill = GridBagConstraints.HORIZONTAL;
+        gridbag.setConstraints(labelService, layoutCons);
+        contentPane.add(labelService);
+
+        String[] serviceTransStrings = new String[serviceCaptionStrings.length];
+        for (int i = 0; i < serviceCaptionStrings.length; i++) {
+            serviceTransStrings[i] = tr(serviceCaptionStrings[i]);
+        }
+        comboBoxService = new JComboBox<String>(serviceTransStrings);
+        comboBoxService.setSelectedIndex(0);
+        layoutCons.gridx = 1;
+        layoutCons.gridy = 4;
+        layoutCons.weightx = 0.5;
+        layoutCons.fill = GridBagConstraints.HORIZONTAL;
+        gridbag.setConstraints(comboBoxService, layoutCons);
+        contentPane.add(comboBoxService);
+
+        checkBoxIsBus = new JCheckBox(tr(BUS_CAPTION));
+        layoutCons.gridx = 0;
+        layoutCons.gridy = 5;
+        layoutCons.weightx = 0.5;
+        layoutCons.fill = GridBagConstraints.HORIZONTAL;
+        gridbag.setConstraints(checkBoxIsBus, layoutCons);
+        checkBoxIsBus.addItemListener(this);
+        contentPane.add(checkBoxIsBus);
+
+        checkBoxIsShareTaxi = new JCheckBox(tr(SHARE_TAXI_CAPTION));
+        layoutCons.gridx = 1;
+        layoutCons.gridy = 5;
+        layoutCons.weightx = 0.5;
+        layoutCons.fill = GridBagConstraints.HORIZONTAL;
+        gridbag.setConstraints(checkBoxIsShareTaxi, layoutCons);
+        checkBoxIsShareTaxi.addItemListener(this);
+        contentPane.add(checkBoxIsShareTaxi);
+
+        checkBoxIsTrolleybus = new JCheckBox(tr(TROLLEYBUS_CAPTION));
+        layoutCons.gridx = 0;
+        layoutCons.gridy = 6;
+        layoutCons.weightx = 0.5;
+        layoutCons.fill = GridBagConstraints.HORIZONTAL;
+        gridbag.setConstraints(checkBoxIsTrolleybus, layoutCons);
+        checkBoxIsTrolleybus.addItemListener(this);
+        contentPane.add(checkBoxIsTrolleybus);
+
+        checkBoxIsBusStation = new JCheckBox(tr(BUS_STATION_CAPTION));
+        layoutCons.gridx = 1;
+        layoutCons.gridy = 6;
+        layoutCons.weightx = 0.5;
+        layoutCons.fill = GridBagConstraints.HORIZONTAL;
+        gridbag.setConstraints(checkBoxIsBusStation, layoutCons);
+        checkBoxIsBusStation.addItemListener(this);
+        contentPane.add(checkBoxIsBusStation);
+
+        checkBoxIsTram = new JCheckBox(tr(TRAM_CAPTION));
+        layoutCons.gridx = 0;
+        layoutCons.gridy = 7;
+        layoutCons.weightx = 0.5;
+        layoutCons.fill = GridBagConstraints.HORIZONTAL;
+        gridbag.setConstraints(checkBoxIsTram, layoutCons);
+        checkBoxIsTram.addItemListener(this);
+        contentPane.add(checkBoxIsTram);
+
+        checkBoxIsTrainStation = new JCheckBox(tr(RAILWAY_STATION_CAPTION));
+        layoutCons.gridx = 0;
+        layoutCons.gridy = 8;
+        layoutCons.weightx = 0.5;
+        layoutCons.fill = GridBagConstraints.HORIZONTAL;
+        gridbag.setConstraints(checkBoxIsTrainStation, layoutCons);
+        checkBoxIsTrainStation.addItemListener(this);
+        contentPane.add(checkBoxIsTrainStation);
+
+        checkBoxIsTrainStop = new JCheckBox(tr(RAILWAY_STOP_CAPTION));
+        layoutCons.gridx = 1;
+        layoutCons.gridy = 8;
+        layoutCons.weightx = 0.5;
+        layoutCons.fill = GridBagConstraints.HORIZONTAL;
+        gridbag.setConstraints(checkBoxIsTrainStop, layoutCons);
+        checkBoxIsTrainStop.addItemListener(this);
+        contentPane.add(checkBoxIsTrainStop);
+
+        checkBoxIsAssignTransportType = new JCheckBox(tr(ASSIGN_TRANSPORT_TYPE_CAPTION));
+        layoutCons.gridx = 0;
+        layoutCons.gridy = 9;
+        layoutCons.weightx = 0.5;
+        layoutCons.fill = GridBagConstraints.HORIZONTAL;
+        gridbag.setConstraints(checkBoxIsAssignTransportType, layoutCons);
+        checkBoxIsAssignTransportType.addItemListener(this);
+        contentPane.add(checkBoxIsAssignTransportType);
+
+        checkBoxIsBench = new JCheckBox(tr(BENCH_CAPTION));
+        layoutCons.gridx = 0;
+        layoutCons.gridy = 10;
+        layoutCons.weightx = 0.5;
+        layoutCons.fill = GridBagConstraints.HORIZONTAL;
+        gridbag.setConstraints(checkBoxIsBench, layoutCons);
+        checkBoxIsBench.addItemListener(this);
+        contentPane.add(checkBoxIsBench);
+
+        checkBoxIsShelder = new JCheckBox(tr(SHELDER_CAPTION));
+        layoutCons.gridx = 1;
+        layoutCons.gridy = 10;
+        layoutCons.weightx = 0.5;
+        layoutCons.fill = GridBagConstraints.HORIZONTAL;
+        gridbag.setConstraints(checkBoxIsShelder, layoutCons);
+        checkBoxIsShelder.addItemListener(this);
+        contentPane.add(checkBoxIsShelder);
+
+        checkBoxIsCover = new JCheckBox(tr(COVER_CAPTION));
+        layoutCons.gridx = 0;
+        layoutCons.gridy = 11;
+        layoutCons.weightx = 0.5;
+        layoutCons.fill = GridBagConstraints.HORIZONTAL;
+        gridbag.setConstraints(checkBoxIsCover, layoutCons);
+        checkBoxIsCover.addItemListener(this);
+        contentPane.add(checkBoxIsCover);
+
+        checkBoxIsArea = new JCheckBox(tr(AREA_CAPTION));
+        layoutCons.gridx = 1;
+        layoutCons.gridy = 11;
+        layoutCons.weightx = 0.5;
+        layoutCons.fill = GridBagConstraints.HORIZONTAL;
+        gridbag.setConstraints(checkBoxIsArea, layoutCons);
+        checkBoxIsArea.addItemListener(this);
+        contentPane.add(checkBoxIsArea);
+
+        JButton buttonSave = new JButton(tr(SAVE_BUTTON_CAPTION));
+        layoutCons.gridx = 0;
+        layoutCons.gridy = 12;
+        layoutCons.weightx = 0.5;
+        layoutCons.fill = GridBagConstraints.HORIZONTAL;
+        layoutCons.insets = new Insets(10, 0, 0, 0);
+        gridbag.setConstraints(buttonSave, layoutCons);
+        buttonSave.setActionCommand(SAVE_COMMAND);
+        buttonSave.addActionListener(this);
+        contentPane.add(buttonSave);
+
+        JButton buttonCancel = new JButton(tr(CANCEL_BUTTON_CAPTION));
+        layoutCons.gridx = 1;
+        layoutCons.gridy = 12;
+        layoutCons.weightx = 0.5;
+        layoutCons.fill = GridBagConstraints.LINE_START;
+        layoutCons.insets = new Insets(10, 0, 0, 0);
+        gridbag.setConstraints(buttonCancel, layoutCons);
+        buttonCancel.setActionCommand(CANCEL_COMMAND);
+        buttonCancel.addActionListener(this);
+        contentPane.add(buttonCancel);
+        return contentPane;
+    }
+
+    /**
+     * Constructor of dialog with filling of controls
+     * 
+     * @param customizeStopAction Stop area customizing action
+     * @param stopArea Stop area
+     */
+    public CustomizePublicTransportStopDialog(CustomizeStopAction customizeStopAction, StopArea stopArea) {
+        this();
+        setValues(stopArea);
+        this.customizeStopAction = customizeStopAction;
+        this.stopArea = stopArea;
+    }
+
+    /**
+     * Return stop area
+     * 
+     * @return Stop area
+     */
+    public StopArea getStopArea() {
+        return stopArea;
+    }
+
+    /**
+     * Set stop area and fill controls
+     * 
+     * @param newStopArea Stop area
+     */
+    public void setStopArea(StopArea newStopArea) {
+        setValues(newStopArea);
+        this.stopArea = newStopArea;
+    }
+
+    /**
+     * Returns stop area customizing action
+     * 
+     * @return Stop area customizing action
+     */
+    public CustomizeStopAction getCustomizeStopAction() {
+        return customizeStopAction;
+    }
+
+    /**
+     * Set stop area customizing action
+     * 
+     * @param newCustomizeStopAction Stop area customizing action
+     */
+    public void setCustomizeStopAction(CustomizeStopAction newCustomizeStopAction) {
+        customizeStopAction = newCustomizeStopAction;
+    }
+
+    /**
+     * Set value in check boxes map
+     * 
+     * @param checkBox Check box
+     * @param value Value of check box
+     */
+    public void setCheckBoxValue(JCheckBox checkBox, Boolean value) {
+        checkBoxValues.put(checkBox, value);
+        checkBox.setSelected(value);
+    }
+
+    /**
+     * Returns value of check box
+     * 
+     * @param checkBox Check box
+     * @return Value of check box
+     */
+    public Boolean getCheckBoxValue(JCheckBox checkBox) {
+        try {
+            if (checkBoxValues.containsKey(checkBox)) {
+                return checkBoxValues.get(checkBox);
+            }
+            return false;
+        } catch (Exception ex) {
+            MessageBox.ok(ex.getMessage());
+        }
+        return false;
+    }
+
+    /**
+     * Callback method for check boxes Set values in check boxes map
+     */
+    @Override
+    public void itemStateChanged(ItemEvent event) {
+        JCheckBox checkBox = (JCheckBox) event.getSource();
+        if (event.getStateChange() == ItemEvent.DESELECTED) {
+            checkBoxValues.put(checkBox, false);
+        } else if (event.getStateChange() == ItemEvent.SELECTED) {
+            checkBoxValues.put(checkBox, true);
+        }
+    }
+
+    /**
+     * Show or hide dialog
+     * 
+     * @param isVisible Flag of dialog visibility
+     */
+    public void setVisible(Boolean isVisible) {
+        if (jDialog != null)
+            jDialog.setVisible(isVisible);
+    }
+
+    /**
+     * Get index of network level
+     * 
+     * @param service Network level name
+     * @return Index of network level
+     */
+    private int getServiceIndex(String service) {
+        for (int i = 0; i < serviceStrings.length; i++) {
+            if (serviceStrings[i].equals(service)) {
+                return i;
+            }
+        }
+        return 0;
+    }
+
+    /**
+     * Setting values of controls from stop area
+     * 
+     * @param stopArea Stop area
+     */
+    public void setValues(StopArea stopArea) {
+        if (stopArea == null)
+            return;
+        if (stopArea.name != null)
+            textFieldName.setText(stopArea.name);
+        else if (previousName != null)
+            textFieldName.setText(previousName);
+        if (stopArea.nameEn != null)
+            textFieldNameEn.setText(stopArea.nameEn);
+        else if (previousNameEn != null)
+            textFieldNameEn.setText(previousNameEn);
+        if (stopArea.network != null)
+            textFieldNetwork.setText(stopArea.network);
+        else if (previousNetwork != null)
+            textFieldNetwork.setText(previousNetwork);
+        if (stopArea.operator != null)
+            textFieldOperator.setText(stopArea.operator);
+        else if (previousOperator != null)
+            textFieldOperator.setText(previousOperator);
+        comboBoxService.setSelectedIndex(getServiceIndex(stopArea.service));
+        setCheckBoxValue(checkBoxIsBus, stopArea.isBus);
+        setCheckBoxValue(checkBoxIsShareTaxi, stopArea.isShareTaxi);
+        setCheckBoxValue(checkBoxIsTrolleybus, stopArea.isTrolleybus);
+        setCheckBoxValue(checkBoxIsBusStation, stopArea.isBusStation);
+        setCheckBoxValue(checkBoxIsAssignTransportType, stopArea.isAssignTransportType);
+        setCheckBoxValue(checkBoxIsTram, stopArea.isTram);
+        setCheckBoxValue(checkBoxIsTrainStation, stopArea.isTrainStation);
+        setCheckBoxValue(checkBoxIsTrainStop, stopArea.isTrainStation);
+        setCheckBoxValue(checkBoxIsTrainStop, stopArea.isTrainStop);
+        setCheckBoxValue(checkBoxIsBench, stopArea.isBench);
+        setCheckBoxValue(checkBoxIsShelder, stopArea.isShelter);
+        setCheckBoxValue(checkBoxIsCover, stopArea.isCovered);
+        setCheckBoxValue(checkBoxIsArea, stopArea.isArea);
+    }
+
+    /**
+     * Returns text box value or null
+     * 
+     * @param textField Text box
+     * @return Text box value or null
+     */
+    public String getTextFromControl(JTextField textField) {
+        if (textField.getText().isEmpty())
+            return null;
+        return textField.getText();
+    }
+
+    /**
+     * Load values from controls and saving in stop area fields
+     * 
+     * @return Stop area
+     */
+    public StopArea saveValues() {
+        StopArea stopArea = this.stopArea;
+        try {
+            if (stopArea == null)
+                stopArea = new StopArea();
+            stopArea.name = getTextFromControl(textFieldName);
+            previousName = stopArea.name;
+            stopArea.nameEn = getTextFromControl(textFieldNameEn);
+            previousNameEn = stopArea.nameEn;
+            stopArea.network = getTextFromControl(textFieldNetwork);
+            previousNetwork = stopArea.network;
+            stopArea.operator = getTextFromControl(textFieldOperator);
+            previousOperator = stopArea.operator;
+            stopArea.service = serviceStrings[comboBoxService.getSelectedIndex()];
+            stopArea.isBus = getCheckBoxValue(checkBoxIsBus);
+            stopArea.isShareTaxi = getCheckBoxValue(checkBoxIsShareTaxi);
+            stopArea.isTrolleybus = getCheckBoxValue(checkBoxIsTrolleybus);
+            stopArea.isBusStation = getCheckBoxValue(checkBoxIsBusStation);
+            stopArea.isAssignTransportType = getCheckBoxValue(checkBoxIsAssignTransportType);
+            stopArea.isTram = getCheckBoxValue(checkBoxIsTram);
+            stopArea.isTrainStation = getCheckBoxValue(checkBoxIsTrainStation);
+            stopArea.isTrainStop = getCheckBoxValue(checkBoxIsTrainStop);
+            stopArea.isBench = getCheckBoxValue(checkBoxIsBench);
+            stopArea.isShelter = getCheckBoxValue(checkBoxIsShelder);
+            stopArea.isCovered = getCheckBoxValue(checkBoxIsCover);
+            stopArea.isArea = getCheckBoxValue(checkBoxIsArea);
+        } catch (Exception ex) {
+            MessageBox.ok(ex.getMessage());
+        }
+        return stopArea;
+    }
+
+    /**
+     * Callback method for buttons event
+     */
+    @Override
+    public void actionPerformed(ActionEvent event) {
+        if (SAVE_COMMAND.equals(event.getActionCommand())) {
+            setVisible(false);
+            if (customizeStopAction != null) {
+                StopArea stopArea = saveValues();
+                customizeStopAction.performCustomizing(stopArea);
+            }
+        } else {
+            setVisible(false);
+        }
+    }
+
+}
Index: applications/editors/josm/plugins/CustomizePublicTransportStop/src/org/openstreetmap/josm/plugins/customizepublictransportstop/CustomizePublicTransportStopPlugin.java
===================================================================
--- applications/editors/josm/plugins/CustomizePublicTransportStop/src/org/openstreetmap/josm/plugins/customizepublictransportstop/CustomizePublicTransportStopPlugin.java	(revision 34501)
+++ applications/editors/josm/plugins/CustomizePublicTransportStop/src/org/openstreetmap/josm/plugins/customizepublictransportstop/CustomizePublicTransportStopPlugin.java	(revision 34501)
@@ -0,0 +1,30 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.customizepublictransportstop;
+
+import org.openstreetmap.josm.gui.MainApplication;
+import org.openstreetmap.josm.plugins.Plugin;
+import org.openstreetmap.josm.plugins.PluginInformation;
+
+/**
+ * Class of plugin of customizing of stop area Plugin for josm editor
+ * 
+ * @author Rodion Scherbakov
+ */
+public class CustomizePublicTransportStopPlugin extends Plugin {
+    /**
+     * Stop area customizing action
+     */
+    private CustomizeStopAction stopAreaCreatorAction;
+
+    /**
+     * Constructor of plug-in object
+     * 
+     * @param info Plug-in properties
+     */
+    public CustomizePublicTransportStopPlugin(PluginInformation info) {
+        super(info);
+        stopAreaCreatorAction = CustomizeStopAction.createCustomizeStopAction();
+        MainApplication.getMenu().toolsMenu.add(stopAreaCreatorAction);
+    }
+
+}
Index: applications/editors/josm/plugins/CustomizePublicTransportStop/src/org/openstreetmap/josm/plugins/customizepublictransportstop/CustomizeStopAction.java
===================================================================
--- applications/editors/josm/plugins/CustomizePublicTransportStop/src/org/openstreetmap/josm/plugins/customizepublictransportstop/CustomizeStopAction.java	(revision 34501)
+++ applications/editors/josm/plugins/CustomizePublicTransportStop/src/org/openstreetmap/josm/plugins/customizepublictransportstop/CustomizeStopAction.java	(revision 34501)
@@ -0,0 +1,98 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.customizepublictransportstop;
+
+import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+
+import org.openstreetmap.josm.actions.JosmAction;
+import org.openstreetmap.josm.tools.Shortcut;
+
+/**
+ * Class of customizing of stop area Action for josm editor
+ * 
+ * @author Rodion Scherbakov
+ */
+public class CustomizeStopAction extends JosmAction implements IStopAreaCustomizer {
+
+    /**
+     * Menu icon file name
+     */
+    private static final String CUSTOMIZE_STOP_ACTION_ICON_NAME = "bus.png";
+    /**
+     * Menu item tooltip
+     */
+    private static final String CUSTOMIZE_STOP_ACTION_MENU_TOOLTIP = "Customize stop under osm public transit standard v2";
+    /**
+     * Menu item caption
+     */
+    private static final String CUSTOMIZE_STOP_ACTION_MENU_NAME = "Customize stop";
+    /**
+     * Serialization UID
+     */
+    private static final long serialVersionUID = 6769508902749446137L;
+
+    /**
+     * Constructor of stop area customizing action
+     * 
+     * @param name Name of action in josm menu
+     * @param iconName Name of icon file for josm menu
+     * @param tooltip Tooltip of action in josm menu
+     * @param shortcut Short key of action on josm
+     * @param registerInToolbar Flag of registration in josm menu
+     */
+    protected CustomizeStopAction(String name, String iconName, String tooltip, Shortcut shortcut,
+            boolean registerInToolbar) {
+        super(name, iconName, tooltip, shortcut, registerInToolbar);
+    }
+
+    /**
+     * Constructs a stop area customizing action.
+     * 
+     * @return the stop area customizing action
+     */
+    public static CustomizeStopAction createCustomizeStopAction() {
+        // CHECKSTYLE.OFF: LineLength
+        CustomizeStopAction action = new CustomizeStopAction(tr(CUSTOMIZE_STOP_ACTION_MENU_NAME),
+                CUSTOMIZE_STOP_ACTION_ICON_NAME, tr(CUSTOMIZE_STOP_ACTION_MENU_TOOLTIP),
+                Shortcut.registerShortcut("tools:customizestop", tr("Tool: {0}", tr(CUSTOMIZE_STOP_ACTION_MENU_NAME)),
+                        KeyEvent.VK_U, Shortcut.DIRECT),
+                true);
+        action.putValue("help", ht("/Action/CustomizeStopAction"));
+        // CHECKSTYLE.ON: LineLength
+        return action;
+    }
+
+    /**
+     * Realization of action Construct stop area object from selected object and
+     * show settings dialog
+     */
+    @Override
+    public void actionPerformed(ActionEvent arg0) {
+        if (!isEnabled())
+            return;
+        CreateStopAreaFromSelectedObjectOperation createStopAreaFromSelectedObjectOperation = new CreateStopAreaFromSelectedObjectOperation(
+                getLayerManager().getEditDataSet());
+        StopArea stopArea = createStopAreaFromSelectedObjectOperation.performCustomizing(null);
+        if (stopArea == null)
+            return;
+        CustomizePublicTransportStopDialog dialog = new CustomizePublicTransportStopDialog(this, stopArea);
+        dialog.setVisible(true);
+    }
+
+    /**
+     * Perform stop area customizing under user selection This method is launched by
+     * stop area settings dialog
+     * 
+     * @param stopArea Stop area object with new settings
+     */
+    @Override
+    public StopArea performCustomizing(StopArea stopArea) {
+        CustomizeStopAreaOperation customizeStopAreaOperation = new CustomizeStopAreaOperation(
+                getLayerManager().getEditDataSet());
+        return customizeStopAreaOperation.performCustomizing(stopArea);
+    }
+
+}
Index: applications/editors/josm/plugins/CustomizePublicTransportStop/src/org/openstreetmap/josm/plugins/customizepublictransportstop/CustomizeStopAreaOperation.java
===================================================================
--- applications/editors/josm/plugins/CustomizePublicTransportStop/src/org/openstreetmap/josm/plugins/customizepublictransportstop/CustomizeStopAreaOperation.java	(revision 34501)
+++ applications/editors/josm/plugins/CustomizePublicTransportStop/src/org/openstreetmap/josm/plugins/customizepublictransportstop/CustomizeStopAreaOperation.java	(revision 34501)
@@ -0,0 +1,581 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.customizepublictransportstop;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.openstreetmap.josm.command.AddCommand;
+import org.openstreetmap.josm.command.ChangeCommand;
+import org.openstreetmap.josm.command.ChangePropertyCommand;
+import org.openstreetmap.josm.command.Command;
+import org.openstreetmap.josm.command.SequenceCommand;
+import org.openstreetmap.josm.data.UndoRedoHandler;
+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;
+import org.openstreetmap.josm.data.osm.RelationMember;
+import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.gui.MainApplication;
+import org.openstreetmap.josm.tools.Logging;
+
+/**
+ * Operation of creation and customizing stop area relation and its members
+ * under user selection
+ * 
+ * @author Rodion Scherbakov
+ */
+public class CustomizeStopAreaOperation extends StopAreaOperationBase {
+
+    /**
+     * Operation name in undo list
+     */
+    private static final String TAG_ASSIGN_COMMAND_NAME = "Stop area tag assign";
+
+    /**
+     * Constructor of operation object
+     * 
+     * @param currentDataSet Current Josm data set
+     */
+    public CustomizeStopAreaOperation(DataSet currentDataSet) {
+        super(currentDataSet);
+    }
+
+    /**
+     * Forming commands for josm for saving name and name:en attributes stop of area
+     * members and relation attributes
+     * 
+     * @param target Stop area member or relation
+     * @param commands List of commands
+     * @param stopArea Stop area object
+     * @return Resulting list of commands
+     */
+    public List<Command> nameTagAssign(OsmPrimitive target, List<Command> commands, StopArea stopArea) {
+        if (commands == null)
+            commands = new ArrayList<Command>();
+
+        commands = assignTag(commands, target, OSMTags.NAME_TAG, "".equals(stopArea.name) ? null : stopArea.name);
+        commands = assignTag(commands, target, OSMTags.NAME_EN_TAG,
+                "".equals(stopArea.nameEn) ? null : stopArea.nameEn);
+        return commands;
+    }
+
+    /**
+     * Clear transport type tags
+     * 
+     * @param target Josm object for tag clearing
+     * @param commands Command list
+     * @return Resulting list of commands
+     */
+    protected List<Command> transportTypeTagClearing(OsmPrimitive target, List<Command> commands) {
+        commands = clearTag(commands, target, OSMTags.BUS_TAG);
+        commands = clearTag(commands, target, OSMTags.SHARE_TAXI_TAG);
+        commands = clearTag(commands, target, OSMTags.TROLLEYBUS_TAG);
+        commands = clearTag(commands, target, OSMTags.TRAM_TAG);
+        commands = clearTag(commands, target, OSMTags.TRAIN_TAG);
+        return commands;
+    }
+
+    /**
+     * Assign transport type tags to node
+     * 
+     * @param target Josm object for tag assigning
+     * @param commands Command list
+     * @param stopArea Stop area object
+     * @param isStopPoint Flag of stop point
+     * @return Resulting list of commands
+     */
+    protected List<Command> transportTypeTagAssign(OsmPrimitive target, List<Command> commands, StopArea stopArea,
+            Boolean isStopPoint) {
+        if (commands == null)
+            commands = new ArrayList<Command>();
+
+        if (isStopPoint) {
+            if (stopArea.isTrainStop || stopArea.isTrainStation) {
+                commands = clearTag(commands, target, OSMTags.BUS_TAG);
+                commands = clearTag(commands, target, OSMTags.SHARE_TAXI_TAG);
+                commands = clearTag(commands, target, OSMTags.TROLLEYBUS_TAG);
+                commands = clearTag(commands, target, OSMTags.TRAM_TAG);
+                commands = assignTag(commands, target, OSMTags.TRAIN_TAG, OSMTags.YES_TAG_VALUE);
+            } else {
+                commands = assignTag(commands, target, OSMTags.BUS_TAG, stopArea.isBus ? OSMTags.YES_TAG_VALUE : null);
+                commands = assignTag(commands, target, OSMTags.SHARE_TAXI_TAG,
+                        stopArea.isShareTaxi ? OSMTags.YES_TAG_VALUE : null);
+                commands = assignTag(commands, target, OSMTags.TROLLEYBUS_TAG,
+                        stopArea.isTrolleybus ? OSMTags.YES_TAG_VALUE : null);
+                commands = assignTag(commands, target, OSMTags.TRAM_TAG,
+                        stopArea.isTram ? OSMTags.YES_TAG_VALUE : null);
+                commands = assignTag(commands, target, OSMTags.TRAIN_TAG,
+                        stopArea.isTrainStation || stopArea.isTrainStop ? OSMTags.YES_TAG_VALUE : null);
+            }
+        } else {
+            if (stopArea.isAssignTransportType) {
+                commands = assignTag(commands, target, OSMTags.BUS_TAG, stopArea.isBus ? OSMTags.YES_TAG_VALUE : null);
+                commands = assignTag(commands, target, OSMTags.SHARE_TAXI_TAG,
+                        stopArea.isShareTaxi ? OSMTags.YES_TAG_VALUE : null);
+                commands = assignTag(commands, target, OSMTags.TROLLEYBUS_TAG,
+                        stopArea.isTrolleybus ? OSMTags.YES_TAG_VALUE : null);
+                commands = assignTag(commands, target, OSMTags.TRAM_TAG,
+                        stopArea.isTram ? OSMTags.YES_TAG_VALUE : null);
+                commands = assignTag(commands, target, OSMTags.TRAIN_TAG,
+                        stopArea.isTrainStation || stopArea.isTrainStop ? OSMTags.YES_TAG_VALUE : null);
+            } else {
+                commands = transportTypeTagClearing(target, commands);
+            }
+        }
+        return commands;
+    }
+
+    /**
+     * Forming commands for josm for saving general attributes of stop area members
+     * and relation
+     * 
+     * @param target Stop area member or relation
+     * @param commands List of commands
+     * @param stopArea Stop area object
+     * @return Resulting list of commands
+     */
+    public List<Command> generalTagAssign(OsmPrimitive target, List<Command> commands, StopArea stopArea) {
+        if (commands == null)
+            commands = new ArrayList<Command>();
+
+        commands = nameTagAssign(target, commands, stopArea);
+        commands = assignTag(commands, target, OSMTags.NETWORK_TAG,
+                "".equals(stopArea.network) ? null : stopArea.network);
+        commands = assignTag(commands, target, OSMTags.OPERATOR_TAG,
+                "".equals(stopArea.operator) ? null : stopArea.operator);
+        commands = assignTag(commands, target, OSMTags.SERVICE_TAG,
+                null == stopArea.service || OSMTags.CITY_NETWORK_TAG_VALUE.equals(stopArea.service) ? null
+                        : stopArea.service);
+
+        return commands;
+    }
+
+    /**
+     * Forming commands for josm for saving stop position attributes
+     * 
+     * @param target Stop position node
+     * @param commands Original command list
+     * @param stopArea Stop area object
+     * @param isFirst true, if target is first stop position in stop area
+     * @return Resulting command list
+     */
+    public List<Command> stopPointTagAssign(OsmPrimitive target, List<Command> commands, StopArea stopArea,
+            Boolean isFirst) {
+        if (commands == null)
+            commands = new ArrayList<Command>();
+
+        commands = generalTagAssign(target, commands, stopArea);
+        commands = transportTypeTagAssign(target, commands, stopArea, true);
+        if (isFirst) {
+            if (stopArea.isTrainStop) {
+                commands = assignTag(commands, target, OSMTags.RAILWAY_TAG, OSMTags.HALT_TAG_VALUE);
+            } else if (stopArea.isTrainStation) {
+                commands = assignTag(commands, target, OSMTags.RAILWAY_TAG, OSMTags.STATION_TAG_VALUE);
+            } else if (stopArea.isTram)
+                commands = assignTag(commands, target, OSMTags.RAILWAY_TAG, OSMTags.TRAM_STOP_TAG_VALUE);
+            else
+                commands = clearTag(commands, target, OSMTags.RAILWAY_TAG);
+        } else {
+            commands = clearTag(commands, target, OSMTags.RAILWAY_TAG);
+        }
+        if (compareTag(target, OSMTags.HIGHWAY_TAG, OSMTags.BUS_STOP_TAG_VALUE))
+            commands = clearTag(commands, target, OSMTags.HIGHWAY_TAG);
+        if (compareTag(target, OSMTags.AMENITY_TAG, OSMTags.BUS_STATION_TAG_VALUE))
+            commands = clearTag(commands, target, OSMTags.AMENITY_TAG);
+        commands = assignTag(commands, target, OSMTags.PUBLIC_TRANSPORT_TAG, OSMTags.STOP_POSITION_TAG_VALUE);
+        return commands;
+    }
+
+    /**
+     * Forming commands for josm for saving platform attributes
+     * 
+     * @param target Platform node or way
+     * @param commands Original command list
+     * @param stopArea Stop area object
+     * @param isSelected true, if this platform is selected in editor
+     * @param isFirst true, if this platform is first in stop area
+     * @return Resulting command list
+     */
+    public List<Command> platformTagAssign(OsmPrimitive target, List<Command> commands, StopArea stopArea,
+            Boolean isFirst) {
+        if (commands == null)
+            commands = new ArrayList<Command>();
+
+        commands = generalTagAssign(target, commands, stopArea);
+        commands = transportTypeTagAssign(target, commands, stopArea, false);
+
+        if (compareTag(target, OSMTags.RAILWAY_TAG, OSMTags.HALT_TAG_VALUE)
+                || compareTag(target, OSMTags.RAILWAY_TAG, OSMTags.STATION_TAG_VALUE))
+            commands = clearTag(commands, target, OSMTags.RAILWAY_TAG);
+        if (target instanceof Way && (stopArea.isTrainStop || stopArea.isTrainStation || stopArea.isTram))
+            commands = assignTag(commands, target, OSMTags.RAILWAY_TAG, OSMTags.PLATFORM_TAG_VALUE);
+        if (stopArea.isBus || stopArea.isShareTaxi || stopArea.isTrolleybus) {
+            if (target instanceof Way)
+                commands = assignTag(commands, target, OSMTags.HIGHWAY_TAG, OSMTags.PLATFORM_TAG_VALUE);
+            else if (isFirst && !stopArea.isBusStation)
+                commands = assignTag(commands, target, OSMTags.HIGHWAY_TAG, OSMTags.BUS_STOP_TAG_VALUE);
+        }
+        commands = assignTag(commands, target, OSMTags.PUBLIC_TRANSPORT_TAG, OSMTags.PLATFORM_TAG_VALUE);
+        if (target == stopArea.selectedObject) {
+            commands = assignTag(commands, target, OSMTags.BENCH_TAG, stopArea.isBench ? OSMTags.YES_TAG_VALUE : null);
+            commands = assignTag(commands, target, OSMTags.SHELTER_TAG,
+                    stopArea.isShelter ? OSMTags.YES_TAG_VALUE : null);
+            commands = assignTag(commands, target, OSMTags.COVERED_TAG,
+                    stopArea.isCovered ? OSMTags.YES_TAG_VALUE : null);
+            commands = assignTag(commands, target, OSMTags.AREA_TAG, stopArea.isArea ? OSMTags.YES_TAG_VALUE : null);
+        }
+        return commands;
+    }
+
+    /**
+     * Forming commands for josm for saving attributes of non stop position or
+     * platform
+     * 
+     * @param target Member of stop area relation
+     * @param commands Original command list
+     * @param stopArea Stop area object
+     * @return Resulting command list
+     */
+    public List<Command> otherMemberTagAssign(OsmPrimitive target, List<Command> commands, StopArea stopArea) {
+        if (commands == null)
+            commands = new ArrayList<Command>();
+
+        commands = nameTagAssign(target, commands, stopArea);
+        commands = clearTag(commands, target, OSMTags.NETWORK_TAG);
+        commands = clearTag(commands, target, OSMTags.OPERATOR_TAG);
+        commands = clearTag(commands, target, OSMTags.SERVICE_TAG);
+        if (compareTag(target, OSMTags.RAILWAY_TAG, OSMTags.HALT_TAG_VALUE)
+                || compareTag(target, OSMTags.RAILWAY_TAG, OSMTags.STATION_TAG_VALUE))
+            commands = clearTag(commands, target, OSMTags.RAILWAY_TAG);
+        return commands;
+    }
+
+    /**
+     * Forming commands for josm for saving stop area relation attributes
+     * 
+     * @param commands Original command list
+     * @param stopArea Stop area object
+     * @return Resulting command list
+     */
+    private List<Command> createStopAreaRelation(List<Command> commands, StopArea stopArea) {
+        if (commands == null)
+            commands = new ArrayList<Command>();
+
+        Relation newRelation = new Relation();
+        for (Node node : stopArea.stopPoints) {
+            newRelation.addMember(new RelationMember(OSMTags.STOP_ROLE, node));
+        }
+        for (OsmPrimitive platform : stopArea.platforms) {
+            newRelation.addMember(new RelationMember(OSMTags.PLATFORM_ROLE, platform));
+        }
+        for (OsmPrimitive otherMember : stopArea.otherMembers) {
+            newRelation.addMember(new RelationMember("", otherMember));
+        }
+        UndoRedoHandler.getInstance().add(new AddCommand(MainApplication.getLayerManager().getEditDataSet(), newRelation));
+        commands = generalTagAssign(newRelation, commands, stopArea);
+        commands = assignTag(commands, newRelation, OSMTags.TYPE_TAG, OSMTags.PUBLIC_TRANSPORT_TAG);
+        commands = assignTag(commands, newRelation, OSMTags.PUBLIC_TRANSPORT_TAG, OSMTags.STOP_AREA_TAG_VALUE);
+        return commands;
+    }
+
+    /**
+     * Adding of new stop area members to relation
+     * 
+     * @param commands Original command list
+     * @param targetRelation Stop area relation
+     * @param member Stop area relation member
+     * @param roleName Role name
+     * @return Resulting command list
+     */
+    public static List<Command> addNewRelationMember(List<Command> commands, Relation targetRelation,
+            OsmPrimitive member, String roleName) {
+        if (commands == null)
+            commands = new ArrayList<Command>();
+
+        for (RelationMember relationMember : targetRelation.getMembers()) {
+            if (relationMember.getMember() == member) {
+                if (relationMember.getRole() == roleName) {
+                    return commands;
+                }
+                return commands;
+            }
+        }
+        targetRelation.addMember(new RelationMember(roleName, member));
+        commands.add(new ChangeCommand(targetRelation, targetRelation));
+        return commands;
+    }
+
+    /**
+     * Adding new stop area members to relation
+     * 
+     * @param commands Original command list
+     * @param stopArea Stop area object
+     * @return Resulting command list
+     */
+    private List<Command> addNewRelationMembers(List<Command> commands, StopArea stopArea) {
+        if (commands == null)
+            commands = new ArrayList<Command>();
+
+        for (OsmPrimitive stopPoint : stopArea.stopPoints) {
+            commands = addNewRelationMember(commands, stopArea.stopAreaRelation, stopPoint, OSMTags.STOP_ROLE);
+        }
+        for (OsmPrimitive platform : stopArea.platforms) {
+            commands = addNewRelationMember(commands, stopArea.stopAreaRelation, platform, OSMTags.PLATFORM_ROLE);
+        }
+        for (OsmPrimitive otherMember : stopArea.otherMembers) {
+            commands = addNewRelationMember(commands, stopArea.stopAreaRelation, otherMember, null);
+        }
+        return commands;
+    }
+
+    /**
+     * Testing, is josm object bus stop node or contains bus stop node, defined by
+     * tag and its value
+     * 
+     * @param member Josm object
+     * @param tag Tag name
+     * @param tagValue Tag value
+     * @return true, if josm object is bus stop node or contains bus stop node
+     */
+    private Node searchBusStop(OsmPrimitive member, String tag, String tagValue) {
+        if (member instanceof Node) {
+            if (compareTag(member, tag, tagValue)) {
+                return (Node) member;
+            }
+        } else {
+            Way memberWay = (Way) member;
+            for (Node node : memberWay.getNodes()) {
+                if (compareTag(node, tag, tagValue)) {
+                    return node;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Testing, do stop area contains bus stop node, defined by tag and its value
+     * 
+     * @param tag Tag name
+     * @param tagValue Tag value
+     * @return true, if stop area contains bus stop node
+     */
+    public Node searchBusStop(StopArea stopArea, String tag, String tagValue) {
+        for (OsmPrimitive platform : stopArea.platforms) {
+            Node busStopNode = searchBusStop(platform, tag, tagValue);
+            if (busStopNode != null)
+                return busStopNode;
+        }
+        for (OsmPrimitive otherMember : stopArea.otherMembers) {
+            Node busStopNode = searchBusStop(otherMember, tag, tagValue);
+            if (busStopNode != null)
+                return busStopNode;
+        }
+        return null;
+    }
+
+    /**
+     * Testing, must stop area to have separate bus stop node
+     * 
+     * @param stopArea Stop area object
+     * @param firstPlatform First platform of stop area JOSM object
+     * @return True, stop area must to have separate bus stop node
+     */
+    public boolean needSeparateBusStop(StopArea stopArea, OsmPrimitive firstPlatform) {
+        if (((stopArea.isBus || stopArea.isShareTaxi || stopArea.isTrolleybus) && (firstPlatform instanceof Way))) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Clear excess tags from JOSM object and its nodes
+     * 
+     * @param commands Original command list
+     * @param target JOSM object
+     * @param tag Tag name
+     * @param tagValue Tag value
+     * @return Resulting command list
+     */
+    private List<Command> clearExcessTags(List<Command> commands, OsmPrimitive target, String tag, String tagValue) {
+        if (commands == null)
+            commands = new ArrayList<Command>();
+
+        if (compareTag(target, tag, tagValue)) {
+            commands = clearTag(commands, target, tag);
+        }
+        if (target instanceof Way) {
+            Way memberWay = (Way) target;
+            for (Node node : memberWay.getNodes()) {
+                if (compareTag(node, tag, tagValue)) {
+                    commands = clearTag(commands, target, tag);
+                }
+            }
+        }
+        return commands;
+    }
+
+    /**
+     * Clear excess tags from JOSM object and its nodes
+     * 
+     * @param commands Command list
+     * @param stopArea Stop area object
+     * @param tag Tag name
+     * @param tagValue Tag value
+     * @return Resulting command list
+     */
+    public List<Command> clearExcessTags(List<Command> commands, StopArea stopArea, String tag, String tagValue) {
+        if (commands == null)
+            commands = new ArrayList<Command>();
+
+        for (OsmPrimitive stopPoint : stopArea.stopPoints) {
+            clearExcessTags(commands, stopPoint, tag, tagValue);
+        }
+        for (OsmPrimitive platform : stopArea.platforms) {
+            clearExcessTags(commands, platform, tag, tagValue);
+        }
+        for (OsmPrimitive otherMember : stopArea.otherMembers) {
+            clearExcessTags(commands, otherMember, tag, tagValue);
+        }
+        return commands;
+    }
+
+    /**
+     * Create separate bus stop node or assign bus stop tag to platform node
+     * 
+     * @param commands Original command list
+     * @param stopArea Stop area object
+     * @param firstPlatform First platform in stop area relation
+     * @param tag Tag name
+     * @param tagValue Tag value
+     * @return Resulting command list
+     */
+    protected List<Command> createSeparateBusStopNode(List<Command> commands, StopArea stopArea,
+            OsmPrimitive firstPlatform, String tag, String tagValue) {
+        if (commands == null)
+            commands = new ArrayList<Command>();
+
+        LatLon centerOfPlatform = getCenterOfWay(firstPlatform);
+        if (firstPlatform instanceof Way) {
+            if (centerOfPlatform != null) {
+                Node newNode = new Node();
+                newNode.setCoor(centerOfPlatform);
+                UndoRedoHandler.getInstance().add(new AddCommand(MainApplication.getLayerManager().getEditDataSet(), newNode));
+                UndoRedoHandler.getInstance().add(new ChangePropertyCommand(newNode, tag, tagValue));
+                commands = assignTag(commands, newNode, tag, tagValue);
+                stopArea.otherMembers.add(newNode);
+            }
+        } else {
+            commands = assignTag(commands, firstPlatform, tag, tagValue);
+        }
+        return commands;
+    }
+
+    /**
+     * Forming commands for JOSM for saving stop area members and relation
+     * attributes
+     * 
+     * @param stopArea Stop area object
+     * @return Resulting command list
+     */
+    public List<Command> customize(StopArea stopArea) {
+        try {
+            List<Command> commands = new ArrayList<Command>();
+            Node separateBusStopNode = searchBusStop(stopArea, OSMTags.AMENITY_TAG, OSMTags.BUS_STATION_TAG_VALUE);
+            if (separateBusStopNode == null)
+                separateBusStopNode = searchBusStop(stopArea, OSMTags.HIGHWAY_TAG, OSMTags.BUS_STOP_TAG_VALUE);
+            if (stopArea.isBusStation) {
+                commands = clearExcessTags(commands, stopArea, OSMTags.HIGHWAY_TAG, OSMTags.BUS_STOP_TAG_VALUE);
+            } else {
+                commands = clearExcessTags(commands, stopArea, OSMTags.AMENITY_TAG, OSMTags.BUS_STATION_TAG_VALUE);
+            }
+            if (!(stopArea.isBus || stopArea.isShareTaxi || stopArea.isTrolleybus)) {
+                commands = clearExcessTags(commands, stopArea, OSMTags.HIGHWAY_TAG, OSMTags.BUS_STOP_TAG_VALUE);
+            }
+            if (stopArea.stopPoints.size() == 0) {
+                CreateNewStopPointOperation createNewStopPointOperation = new CreateNewStopPointOperation(
+                        getCurrentDataSet());
+                createNewStopPointOperation.performCustomizing(stopArea);
+            }
+            Boolean isFirst = true;
+            for (Node node : stopArea.stopPoints) {
+                commands = stopPointTagAssign(node, commands, stopArea, isFirst);
+                isFirst = false;
+            }
+            isFirst = true;
+            OsmPrimitive firstPlatform = null;
+            for (OsmPrimitive platform : stopArea.platforms) {
+                commands = platformTagAssign(platform, commands, stopArea, isFirst);
+                if (isFirst)
+                    firstPlatform = platform;
+                isFirst = false;
+            }
+            if (needSeparateBusStop(stopArea, firstPlatform)) {
+                if (stopArea.isBusStation) {
+                    if (separateBusStopNode == null) {
+                        commands = createSeparateBusStopNode(commands, stopArea, firstPlatform, OSMTags.AMENITY_TAG,
+                                OSMTags.BUS_STATION_TAG_VALUE);
+                    } else {
+                        commands = assignTag(commands, separateBusStopNode, OSMTags.AMENITY_TAG,
+                                OSMTags.BUS_STATION_TAG_VALUE);
+                    }
+                } else {
+                    if (separateBusStopNode == null) {
+                        commands = createSeparateBusStopNode(commands, stopArea, firstPlatform, OSMTags.HIGHWAY_TAG,
+                                OSMTags.BUS_STOP_TAG_VALUE);
+                    } else {
+                        commands = assignTag(commands, separateBusStopNode, OSMTags.HIGHWAY_TAG,
+                                OSMTags.BUS_STOP_TAG_VALUE);
+                    }
+                }
+            } else {
+                if (stopArea.isBusStation) {
+                    commands = assignTag(commands, firstPlatform, OSMTags.AMENITY_TAG, OSMTags.BUS_STATION_TAG_VALUE);
+                } else if (stopArea.isBus || stopArea.isTrolleybus || stopArea.isShareTaxi) {
+                    commands = assignTag(commands, firstPlatform, OSMTags.HIGHWAY_TAG, OSMTags.BUS_STOP_TAG_VALUE);
+                }
+            }
+            for (OsmPrimitive otherMember : stopArea.otherMembers) {
+                commands = otherMemberTagAssign(otherMember, commands, stopArea);
+            }
+            if (stopArea.stopAreaRelation == null) {
+                if (stopArea.stopPoints.size() + stopArea.platforms.size() + stopArea.otherMembers.size() > 1) {
+                    commands = createStopAreaRelation(commands, stopArea);
+                }
+            } else {
+                commands = generalTagAssign(stopArea.stopAreaRelation, commands, stopArea);
+                commands = transportTypeTagClearing(stopArea.stopAreaRelation, commands);
+                commands = addNewRelationMembers(commands, stopArea);
+            }
+            return commands;
+        } catch (Exception ex) {
+            MessageBox.ok(ex.getMessage());
+        }
+        return null;
+    }
+
+    /**
+     * Construct and executing command list for customizing of stop area relation
+     * and its members
+     * 
+     * @param stopArea Stop area object
+     * @return Stop area object
+     */
+    @Override
+    public StopArea performCustomizing(StopArea stopArea) {
+        List<Command> commands = customize(stopArea);
+        if (commands != null && !commands.isEmpty())
+            try {
+                UndoRedoHandler.getInstance().add(new SequenceCommand(tr(TAG_ASSIGN_COMMAND_NAME), commands));
+                return stopArea;
+            } catch (Exception ex) {
+                Logging.error(ex);
+            }
+        return stopArea;
+    }
+
+}
Index: applications/editors/josm/plugins/CustomizePublicTransportStop/src/org/openstreetmap/josm/plugins/customizepublictransportstop/IStopAreaCustomizer.java
===================================================================
--- applications/editors/josm/plugins/CustomizePublicTransportStop/src/org/openstreetmap/josm/plugins/customizepublictransportstop/IStopAreaCustomizer.java	(revision 34501)
+++ applications/editors/josm/plugins/CustomizePublicTransportStop/src/org/openstreetmap/josm/plugins/customizepublictransportstop/IStopAreaCustomizer.java	(revision 34501)
@@ -0,0 +1,17 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.customizepublictransportstop;
+
+/**
+ * Interface of operation of stop area customizing
+ * 
+ * @author Rodion Scherbakov
+ */
+public interface IStopAreaCustomizer {
+    /**
+     * Perform operation of customizing of stop area
+     * 
+     * @param stopArea Stop area
+     * @return Stop area after customizing
+     */
+    StopArea performCustomizing(StopArea stopArea);
+}
Index: applications/editors/josm/plugins/CustomizePublicTransportStop/src/org/openstreetmap/josm/plugins/customizepublictransportstop/MessageBox.java
===================================================================
--- applications/editors/josm/plugins/CustomizePublicTransportStop/src/org/openstreetmap/josm/plugins/customizepublictransportstop/MessageBox.java	(revision 34501)
+++ applications/editors/josm/plugins/CustomizePublicTransportStop/src/org/openstreetmap/josm/plugins/customizepublictransportstop/MessageBox.java	(revision 34501)
@@ -0,0 +1,89 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.customizepublictransportstop;
+
+import java.awt.Component;
+
+import javax.swing.JOptionPane;
+
+/**
+ * MessageBox static class It is used for debug. Source: Java forums
+ * <a>http://www.java-forums.org/java-tip/6578-messagebox-example.html</a>
+ * 
+ * @author Moderator
+ */
+public final class MessageBox {
+    /*
+     * These are a list of STATIC MODAL dialogs
+     * 
+     * int return codes of button pressed:
+     * 
+     * -1 - WINDOW CLOSED - the X PRESSED 0 - YES and OK 1 - NO 2 - CANCEL
+     * 
+     * (thanks to flipside for the idea)
+     */
+
+    /**
+     * Show message box with "yes" and "no" buttons
+     * 
+     * @param theMessage Message for user
+     * @return Code of pressed button
+     */
+    public static int yesno(String theMessage) {
+        int result = JOptionPane.showConfirmDialog((Component) null, theMessage, "alert", JOptionPane.YES_NO_OPTION);
+        return result;
+    }
+
+    /**
+     * Show message box with "yes", "no" and "cancel" buttons
+     * 
+     * @param theMessage Message for user
+     * @return Code of pressed button
+     */
+    public static int yesnocancel(String theMessage) {
+        int result = JOptionPane.showConfirmDialog((Component) null, theMessage, "alert",
+                JOptionPane.YES_NO_CANCEL_OPTION);
+        return result;
+    }
+
+    /**
+     * Show message box with "Ok" and "Cancel" buttons
+     * 
+     * @param theMessage Message for user
+     * @return Code of pressed button
+     */
+    public static int okcancel(String theMessage) {
+        int result = JOptionPane.showConfirmDialog((Component) null, theMessage, "alert", JOptionPane.OK_CANCEL_OPTION);
+        return result;
+    }
+
+    /**
+     * Show message box with "ok" button
+     * 
+     * @param theMessage Message for user
+     * @return Code of pressed button
+     */
+    public static int ok(String theMessage) {
+        int result = JOptionPane.showConfirmDialog((Component) null, theMessage, "alert", JOptionPane.DEFAULT_OPTION);
+        return result;
+    }
+
+    /**
+     * Main method for test launch
+     * 
+     * @param args Arguments of command line
+     */
+    public static void main(String[] args) {
+        int i = MessageBox.yesno("Are your sure ?");
+        System.out.println("ret : " + i);
+        i = MessageBox.yesnocancel("Are your sure ?");
+        System.out.println("ret : " + i);
+        i = MessageBox.okcancel("Are your sure ?");
+        System.out.println("ret : " + i);
+        i = MessageBox.ok("Done.");
+        System.out.println("ret : " + i);
+    }
+
+    private MessageBox() {
+        // Hide default constructor
+    }
+}
Index: applications/editors/josm/plugins/CustomizePublicTransportStop/src/org/openstreetmap/josm/plugins/customizepublictransportstop/NearestWaySegment.java
===================================================================
--- applications/editors/josm/plugins/CustomizePublicTransportStop/src/org/openstreetmap/josm/plugins/customizepublictransportstop/NearestWaySegment.java	(revision 34501)
+++ applications/editors/josm/plugins/CustomizePublicTransportStop/src/org/openstreetmap/josm/plugins/customizepublictransportstop/NearestWaySegment.java	(revision 34501)
@@ -0,0 +1,38 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.customizepublictransportstop;
+
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.WaySegment;
+
+/**
+ * Distance from platform to ways
+ * 
+ * @author Rodion Scherbakov
+ */
+public class NearestWaySegment {
+    /**
+     * Square of distance
+     */
+    public Double distanceSq = 1000000000.0;
+    /**
+     * Way segment
+     */
+    public WaySegment waySegment;
+    /**
+     * Node
+     */
+    public Node newNode;
+
+    /**
+     * Constructor
+     * 
+     * @param distanceSq Square of distance
+     * @param waySegment Way segment
+     * @param newNode Node
+     */
+    public NearestWaySegment(Double distanceSq, WaySegment waySegment, Node newNode) {
+        this.distanceSq = distanceSq;
+        this.waySegment = waySegment;
+        this.newNode = newNode;
+    }
+}
Index: applications/editors/josm/plugins/CustomizePublicTransportStop/src/org/openstreetmap/josm/plugins/customizepublictransportstop/OSMTags.java
===================================================================
--- applications/editors/josm/plugins/CustomizePublicTransportStop/src/org/openstreetmap/josm/plugins/customizepublictransportstop/OSMTags.java	(revision 34501)
+++ applications/editors/josm/plugins/CustomizePublicTransportStop/src/org/openstreetmap/josm/plugins/customizepublictransportstop/OSMTags.java	(revision 34501)
@@ -0,0 +1,70 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.customizepublictransportstop;
+
+/**
+ * OSM object tags
+ * 
+ * @author Rodion Scherbakov
+ */
+public final class OSMTags {
+    public static final String TERTIARY_LINK_TAG_VALUE = "tertiary_link";
+    public static final String SECONDARY_LINK_TAG_VALUE = "secondary_link";
+    public static final String PRIMARY_LINK_TAG_VALUE = "primary_link";
+    public static final String TRUNK_LINK_TAG_VALUE = "trunk_link";
+    public static final String ROAD_TAG_VALUE = "road";
+    public static final String BUS_GUIDEWAY_TAG_VALUE = "bus_guideway";
+    public static final String SERVICE_TAG_VALUE = "service";
+    public static final String RESIDENTIAL_TAG_VALUE = "residential";
+    public static final String UNCLASSIFIED_TAG_VALUE = "unclassified";
+    public static final String TERTIARY_TAG_VALUE = "tertiary";
+    public static final String SECONDARY_TAG_VALUE = "secondary";
+    public static final String PRIMARY_TAG_VALUE = "primary";
+    public static final String TRUNK_TAG_VALUE = "trunk";
+    public static final String TRAM_TAG_VALUE = "tram";
+    public static final String USAGE_TAG = "usage";
+    public static final String MAIN_TAG_VALUE = "main";
+    public static final String RAIL_TAG_VALUE = "rail";
+
+    public static final String AREA_TAG = "area";
+    public static final String COVERED_TAG = "covered";
+    public static final String SHELTER_TAG = "shelter";
+    public static final String BENCH_TAG = "bench";
+    public static final String TRAIN_TAG = "train";
+    public static final String STOP_POSITION_TAG_VALUE = "stop_position";
+    public static final String STATION_TAG_VALUE = "station";
+    public static final String HALT_TAG_VALUE = "halt";
+    public static final String YES_TAG_VALUE = "yes";
+    public static final String RAILWAY_TAG = "railway";
+    public static final String TRAM_STOP_TAG_VALUE = "tram_stop";
+    public static final String TRAM_TAG = "tram";
+    public static final String SHARE_TAXI_TAG = "share_taxi";
+    public static final String TROLLEYBUS_TAG = "trolleybus";
+    public static final String BUS_TAG = "bus";
+    public static final String NETWORK_TAG = "network";
+    public static final String OPERATOR_TAG = "operator";
+    public static final String NAME_EN_TAG = "name:en";
+    public static final String NAME_TAG = "name";
+    public static final String HIGHWAY_TAG = "highway";
+    public static final String AMENITY_TAG = "amenity";
+    public static final String BUS_STATION_TAG_VALUE = "bus_station";
+
+    public static final String BUS_STOP_TAG_VALUE = "bus_stop";
+    public static final String TYPE_TAG = "type";
+    public static final String PUBLIC_TRANSPORT_TAG = "public_transport";
+    public static final String STOP_AREA_TAG_VALUE = "stop_area";
+    public static final String STOP_ROLE = "stop";
+    public static final String PLATFORM_ROLE = "platform";
+    public static final String PLATFORM_TAG_VALUE = "platform";
+    public static final String SERVICE_TAG = "service";
+
+    public static final String CITY_NETWORK_TAG_VALUE = "city";
+    public static final String COMMUTER_NETWORK_TAG_VALUE = "commuter";
+    public static final String LOCAL_NETWORK_TAG_VALUE = "local";
+    public static final String REGIONAL_NETWORK_TAG_VALUE = "regional";
+    public static final String LONG_DISTANCE_NETWORK_TAG_VALUE = "long_distance";
+    public static final String HIGH_SPEED_NETWORK_TAG_VALUE = "high_speed";
+
+    private OSMTags() {
+        // Hide default constructor
+    }
+}
Index: applications/editors/josm/plugins/CustomizePublicTransportStop/src/org/openstreetmap/josm/plugins/customizepublictransportstop/StopArea.java
===================================================================
--- applications/editors/josm/plugins/CustomizePublicTransportStop/src/org/openstreetmap/josm/plugins/customizepublictransportstop/StopArea.java	(revision 34501)
+++ applications/editors/josm/plugins/CustomizePublicTransportStop/src/org/openstreetmap/josm/plugins/customizepublictransportstop/StopArea.java	(revision 34501)
@@ -0,0 +1,153 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.customizepublictransportstop;
+
+import java.util.ArrayList;
+
+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.Way;
+
+/**
+ * Stop area settings
+ * 
+ * @author Rodion Scherbakov
+ */
+public class StopArea {
+
+    /**
+     * Name of stop area
+     */
+    public String name = null;
+    /**
+     * English name of stop area
+     */
+    public String nameEn = null;
+    /**
+     * Operator of stop area
+     */
+    public String operator = null;
+    /**
+     * Network name
+     */
+    public String network = null;
+    /**
+     * Level of network including this stop area
+     */
+    public String service = null;
+    /**
+     * Flag of bus stop area
+     */
+    public Boolean isBus = false;
+    /**
+     * Flag of trolleybus stop area
+     */
+    public Boolean isTrolleybus = false;
+    /**
+     * Flag of share taxi stop area
+     */
+    public Boolean isShareTaxi = false;
+    /**
+     * Flag of bus station stop area
+     */
+    public Boolean isBusStation = false;
+    /**
+     * Flag of tram stop area
+     */
+    public Boolean isTram = false;
+    /**
+     * Flag of railway stop area
+     */
+    public Boolean isTrainStop = false;
+    /**
+     * Flag of railway station
+     */
+    public Boolean isTrainStation = false;
+    /**
+     * Flag of bench on selected platform
+     */
+    public Boolean isAssignTransportType = false;
+    /**
+     * Flag of bench near platform
+     */
+    public Boolean isBench = false;
+    /**
+     * Flag of covered platform
+     */
+    public Boolean isCovered = false;
+    /**
+     * Flag of shelter on selected platform
+     */
+    public Boolean isShelter = false;
+    /**
+     * Relation of stop area
+     */
+    public Relation stopAreaRelation = null;
+    /**
+     * Flag of existing of stop position
+     */
+    public Boolean isStopPointExists = false;
+    /**
+     * Flag of area platform
+     */
+    public Boolean isArea = false;
+    /**
+     * Separate node of bus stop or bus station
+     */
+    public Node separateBusStopNode = null;
+
+    /**
+     * List of nodes of stop positions
+     */
+    public final ArrayList<Node> stopPoints = new ArrayList<Node>();
+    /**
+     * List of josm objects of platforms
+     */
+    public final ArrayList<OsmPrimitive> platforms = new ArrayList<OsmPrimitive>();
+    /**
+     * List of non stop positions or platform stop area members
+     */
+    public final ArrayList<OsmPrimitive> otherMembers = new ArrayList<OsmPrimitive>();
+
+    /**
+     * Selected josm objects. Must be a platform
+     */
+    public OsmPrimitive selectedObject = null;
+
+    /**
+     * Constructor of stop area object
+     */
+    public StopArea() {
+    }
+
+    /**
+     * Constructor of stop area object from selected object
+     * 
+     * @param selectedObject Selected object
+     */
+    public StopArea(OsmPrimitive selectedObject) {
+        this.selectedObject = selectedObject;
+    }
+
+    /**
+     * Get selected in editor node
+     * 
+     * @return Selected node or null
+     */
+    public Node getSelectedNode() {
+        if (selectedObject instanceof Node)
+            return (Node) selectedObject;
+        return null;
+    }
+
+    /**
+     * Get selected way
+     * 
+     * @return Selected way or null
+     */
+    public Way getSelectedWay() {
+        if (selectedObject instanceof Way)
+            return (Way) selectedObject;
+        return null;
+    }
+}
Index: applications/editors/josm/plugins/CustomizePublicTransportStop/src/org/openstreetmap/josm/plugins/customizepublictransportstop/StopAreaOperationBase.java
===================================================================
--- applications/editors/josm/plugins/CustomizePublicTransportStop/src/org/openstreetmap/josm/plugins/customizepublictransportstop/StopAreaOperationBase.java	(revision 34501)
+++ applications/editors/josm/plugins/CustomizePublicTransportStop/src/org/openstreetmap/josm/plugins/customizepublictransportstop/StopAreaOperationBase.java	(revision 34501)
@@ -0,0 +1,131 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.customizepublictransportstop;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.openstreetmap.josm.command.ChangePropertyCommand;
+import org.openstreetmap.josm.command.Command;
+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.Way;
+
+/**
+ * Base class of operation of customizing of stop area
+ * 
+ * @author Rodion Scherbakov
+ */
+public abstract class StopAreaOperationBase implements IStopAreaCustomizer {
+
+    /**
+     * Current dataset of Josm
+     */
+    private DataSet _CurrentDataSet;
+
+    /**
+     * Constructor of operation of customizing of stop area
+     * 
+     * @param currentDataSet Current data set of JOSM
+     */
+    public StopAreaOperationBase(DataSet currentDataSet) {
+        _CurrentDataSet = currentDataSet;
+    }
+
+    /**
+     * Get current dataset of Josm Used for comparability wit previous version
+     * 
+     * @return Current dataset of Josm
+     */
+    protected DataSet getCurrentDataSet() {
+        return _CurrentDataSet;
+    }
+
+    /**
+     * Perform operation of customizing of stop area
+     * 
+     * @param stopArea Stop area object
+     * @return stopArea Resulting stop area object
+     */
+    @Override
+    public abstract StopArea performCustomizing(StopArea stopArea);
+
+    /**
+     * Get tag value of JOSM object
+     * 
+     * @param member JOSM object
+     * @param tagName Tag name
+     * @return Tag value
+     */
+    public static String getTagValue(OsmPrimitive member, String tagName) {
+        return member.getKeys().get(tagName);
+    }
+
+    /**
+     * Comparing of value of tag for josm object
+     * 
+     * @param osmObject JOSM object
+     * @param tagName Tag name
+     * @param tagValue Tag value
+     * @return true, if tag exists and equals tagValue
+     */
+    public static Boolean compareTag(OsmPrimitive osmObject, String tagName, String tagValue) {
+        String value = osmObject.getKeys().get(tagName);
+        if (value != null)
+            return value.equals(tagValue);
+        return false;
+    }
+
+    /**
+     * Assign tag value to JOSM object
+     * 
+     * @param commands Command list
+     * @param target Target OSM object
+     * @param tag Tag name
+     * @param tagValue Tag value
+     * @return Resulting command list
+     */
+    public static List<Command> assignTag(List<Command> commands, OsmPrimitive target, String tag, String tagValue) {
+        if (commands == null)
+            commands = new ArrayList<Command>();
+        commands.add(new ChangePropertyCommand(target, tag, tagValue));
+        return commands;
+    }
+
+    /**
+     * Clear tag value of JOSM object
+     * 
+     * @param commands Command list
+     * @param target Target OSM object
+     * @param tag Tag name
+     * @return Resulting command list
+     */
+    public static List<Command> clearTag(List<Command> commands, OsmPrimitive target, String tag) {
+        return assignTag(commands, target, tag, null);
+    }
+
+    /**
+     * Calculation of center of platform, if platform is way
+     * 
+     * @param platform Platform primitive
+     * @return Coordinates of center of platform
+     */
+    public static LatLon getCenterOfWay(OsmPrimitive platform) {
+        if (platform instanceof Way) {
+            // p = mapView.getPoint((Node) stopArea.selectedObject);
+            Double sumLat = 0.0;
+            Double sumLon = 0.0;
+            Integer countNode = 0;
+            for (Node node : ((Way) platform).getNodes()) {
+                LatLon coord = node.getCoor();
+                sumLat += coord.getX();
+                sumLon += coord.getY();
+                countNode++;
+            }
+            return new LatLon(sumLon / countNode, sumLat / countNode);
+        }
+        return null;
+    }
+
+}
