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