001    // License: GPL. For details, see LICENSE file.
002    package org.openstreetmap.josm.io;
003    
004    import static org.openstreetmap.josm.tools.I18n.tr;
005    
006    import java.io.PrintWriter;
007    import java.io.StringWriter;
008    import java.util.Collection;
009    
010    import org.openstreetmap.josm.data.osm.Changeset;
011    import org.openstreetmap.josm.data.osm.IPrimitive;
012    
013    /**
014     * Creates an OsmChange document from JOSM edits.
015     * See http://wiki.openstreetmap.org/index.php/OsmChange for a documentation of the
016     * OsmChange format.
017     *
018     */
019    public class OsmChangeBuilder {
020        static public final String DEFAULT_API_VERSION = "0.6";
021    
022        private String currentMode;
023        private PrintWriter writer;
024        private StringWriter swriter;
025        private OsmWriter osmwriter;
026        private String apiVersion = DEFAULT_API_VERSION;
027        private boolean prologWritten = false;
028    
029        public OsmChangeBuilder(Changeset changeset) {
030            this(changeset, null /* default api version */);
031        }
032    
033        public OsmChangeBuilder(Changeset changeset, String apiVersion) {
034            this.apiVersion = apiVersion == null ? DEFAULT_API_VERSION : apiVersion;
035            writer = new PrintWriter(swriter = new StringWriter());
036            osmwriter = OsmWriterFactory.createOsmWriter(writer, false, apiVersion);
037            osmwriter.setChangeset(changeset);
038        }
039    
040        protected void write(IPrimitive p) {
041            if (p.isDeleted()) {
042                switchMode("delete");
043                osmwriter.setWithBody(false);
044                p.visit(osmwriter);
045            } else {
046                switchMode(p.isNew() ? "create" : "modify");
047                osmwriter.setWithBody(true);
048                p.visit(osmwriter);
049            }
050        }
051    
052        private void switchMode(String newMode) {
053            if ((newMode != null && !newMode.equals(currentMode))||(newMode == null && currentMode != null)) {
054                if (currentMode != null) {
055                    writer.print("</");
056                    writer.print(currentMode);
057                    writer.println(">");
058                }
059                if (newMode != null) {
060                    writer.print("<");
061                    writer.print(newMode);
062                    writer.println(">");
063                }
064                currentMode = newMode;
065            }
066        }
067    
068        /**
069         * Writes the prolog of the OsmChange document
070         *
071         * @throws IllegalStateException thrown if the prologs has already been written
072         */
073        public void start() throws IllegalStateException{
074            if (prologWritten)
075                throw new IllegalStateException(tr("Prolog of OsmChange document already written. Please write only once."));
076            writer.print("<osmChange version=\"");
077            writer.print(apiVersion);
078            writer.println("\" generator=\"JOSM\">");
079            prologWritten=true;
080        }
081    
082        /**
083         * Appends a collection of Primitives to the OsmChange document.
084         *
085         * @param primitives the collection of primitives. Ignored if null.
086         * @throws IllegalStateException thrown if the prologs has not been written yet
087         * @see #start()
088         * @see #append(IPrimitive)
089         */
090        public void append(Collection<? extends IPrimitive> primitives) throws IllegalStateException{
091            if (primitives == null) return;
092            if (!prologWritten)
093                throw new IllegalStateException(tr("Prolog of OsmChange document not written yet. Please write first."));
094            for (IPrimitive p : primitives) {
095                write(p);
096            }
097        }
098    
099        /**
100         * Appends an Primitive to the OsmChange document.
101         *
102         * @param p the primitive. Ignored if null.
103         * @throws IllegalStateException thrown if the prologs has not been written yet
104         * @see #start()
105         * @see #append(Collection)
106    
107         */
108        public void append(IPrimitive p) {
109            if (p == null) return;
110            if (!prologWritten)
111                throw new IllegalStateException(tr("Prolog of OsmChange document not written yet. Please write first."));
112            write(p);
113        }
114    
115        /**
116         * Writes the epilog of the OsmChange document
117         *
118         * @throws IllegalStateException thrown if the prologs has not been written yet
119         */
120        public void finish() throws IllegalStateException {
121            if (!prologWritten)
122                throw new IllegalStateException(tr("Prolog of OsmChange document not written yet. Please write first."));
123            if (currentMode != null) {
124                writer.print("</");
125                writer.print(currentMode);
126                writer.println(">");
127            }
128            writer.println("</osmChange>");
129        }
130    
131        public String getDocument() {
132            return swriter.toString();
133        }
134    }