package ext_tools;
import static org.openstreetmap.josm.tools.I18n.tr;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.openstreetmap.josm.command.AddCommand;
import org.openstreetmap.josm.command.ChangeCommand;
import org.openstreetmap.josm.command.ChangeNodesCommand;
import org.openstreetmap.josm.command.Command;
import org.openstreetmap.josm.data.osm.*;
final class DataSetToCmd {
/** the source dataset where primitives are merged from */
private final DataSet sourceDataSet;
/**
* A map of all primitives that got replaced with other primitives. Key is
* the PrimitiveId in their dataset, the value is the PrimitiveId in my
* dataset
*/
private final Map<PrimitiveId, OsmPrimitive> mergedMap = new HashMap<>();
private final LinkedList<Command> cmds = new LinkedList<>();
/**
* constructor
*/
public DataSetToCmd(DataSet sourceDataSet) {
this.sourceDataSet = sourceDataSet;
merge();
}
/**
* Merges a primitive <code>other</code> of type
* <P>
* onto my primitives.
*
* @param <P>
* the type of the other primitive
* @param source
* the other primitive
*/
private void mergePrimitive(OsmPrimitive source) {
OsmPrimitive target = null;
switch (source.getType()) {
case NODE:
target = new Node();
break;
case WAY:
target = new Way();
break;
case RELATION:
target = new Relation();
break;
default:
throw new AssertionError();
}
target.mergeFrom(source);
mergedMap.put(source.getPrimitiveId(), target);
cmds.add(new AddCommand(target));
}
private OsmPrimitive getMergeTarget(OsmPrimitive mergeSource)
throws IllegalStateException {
OsmPrimitive target = mergedMap.get(mergeSource.getPrimitiveId());
if (target == null)
return null;
return target;
}
/**
* Postprocess the dataset and fix all merged references to point to the
* actual data.
*/
public void fixReferences() {
for (Way w : sourceDataSet.getWays()) {
mergeNodeList(w);
}
for (Relation r : sourceDataSet.getRelations()) {
mergeRelationMembers(r);
}
}
/**
* Merges the node list of a source way onto its target way.
*
* @param source
* the source way
* @throws IllegalStateException
* thrown if no target way can be found for the source way
* @throws IllegalStateException
* thrown if there isn't a target node for one of the nodes in
* the source way
*
*/
private void mergeNodeList(Way source) throws IllegalStateException {
Way target = (Way) getMergeTarget(source);
if (target == null)
throw new IllegalStateException(tr(
"Missing merge target for way with id {0}", source.getUniqueId()));
if (target.getDataSet() != null)
throw new IllegalStateException(tr(
"Missing merge target for way with id {0}", source.getUniqueId()));
List<Node> newNodes = new ArrayList<>(source.getNodesCount());
for (Node sourceNode : source.getNodes()) {
Node targetNode = (Node) getMergeTarget(sourceNode);
if (targetNode == null)
throw new IllegalStateException(tr(
"Missing merge target for node with id {0}", sourceNode
.getUniqueId()));
if (targetNode.getDataSet() != null)
throw new IllegalStateException(tr(
"Missing merge target for way with id {0}", source.getUniqueId()));
newNodes.add(targetNode);
}
cmds.add(new ChangeNodesCommand(target, newNodes));
}
/**
* Merges the relation members of a source relation onto the corresponding
* target relation.
*
* @param source
* the source relation
* @throws IllegalStateException
* thrown if there is no corresponding target relation
* @throws IllegalStateException
* thrown if there isn't a corresponding target object for one
* of the relation members in source
*/
private void mergeRelationMembers(Relation source) throws IllegalStateException {
Relation target = (Relation) getMergeTarget(source);
if (target == null)
throw new IllegalStateException(
tr("Missing merge target for relation with id {0}", source
.getUniqueId()));
if (target.getDataSet() != null)
throw new IllegalStateException(
tr("Missing merge target for relation with id {0}", source
.getUniqueId()));
LinkedList<RelationMember> newMembers = new LinkedList<>();
for (RelationMember sourceMember : source.getMembers()) {
OsmPrimitive targetMember = getMergeTarget(sourceMember.getMember());
if (targetMember == null)
throw new IllegalStateException(tr(
"Missing merge target of type {0} with id {1}", sourceMember
.getType(), sourceMember.getUniqueId()));
if (targetMember.getDataSet() != null)
throw new IllegalStateException(tr(
"Missing merge target of type {0} with id {1}", sourceMember
.getType(), sourceMember.getUniqueId()));
newMembers.add(new RelationMember(sourceMember.getRole(), targetMember));
}
Relation newRelation = new Relation(target);
newRelation.setMembers(newMembers);
cmds.add(new ChangeCommand(target, newRelation));
}
private void merge() {
for (Node node : sourceDataSet.getNodes()) {
mergePrimitive(node);
}
for (Way way : sourceDataSet.getWays()) {
mergePrimitive(way);
}
for (Relation relation : sourceDataSet.getRelations()) {
mergePrimitive(relation);
}
fixReferences();
}
public LinkedList<Command> getCommandList() {
return cmds;
}
}