package org.osm2world.core.osm.creation;
import static org.openstreetmap.josm.plugins.graphview.core.data.EmptyTagGroup.EMPTY_TAG_GROUP;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.openstreetmap.josm.plugins.graphview.core.data.MapBasedTagGroup;
import org.openstreetmap.josm.plugins.graphview.core.data.TagGroup;
import org.openstreetmap.osmosis.core.container.v0_6.EntityContainer;
import org.openstreetmap.osmosis.core.domain.v0_6.Bound;
import org.openstreetmap.osmosis.core.domain.v0_6.Entity;
import org.openstreetmap.osmosis.core.domain.v0_6.EntityType;
import org.openstreetmap.osmosis.core.domain.v0_6.Node;
import org.openstreetmap.osmosis.core.domain.v0_6.Relation;
import org.openstreetmap.osmosis.core.domain.v0_6.Tag;
import org.openstreetmap.osmosis.core.domain.v0_6.Way;
import org.openstreetmap.osmosis.core.domain.v0_6.WayNode;
import org.openstreetmap.osmosis.core.task.v0_6.RunnableSource;
import org.openstreetmap.osmosis.core.task.v0_6.Sink;
import org.osm2world.core.osm.data.OSMData;
import org.osm2world.core.osm.data.OSMElement;
import org.osm2world.core.osm.data.OSMMember;
import org.osm2world.core.osm.data.OSMNode;
import org.osm2world.core.osm.data.OSMRelation;
import org.osm2world.core.osm.data.OSMWay;
/**
* reads OSM data from an osmosis {@link RunnableSource}.
* Can also be used as a base class for other {@link OSMDataReader} implementations.
*/
public class OsmosisReader implements OSMDataReader {
private final RunnableSource source;
private boolean complete = false;
private synchronized boolean isComplete() {
return complete;
}
private synchronized void setCompleteTrue() {
this.complete = true;
}
private List<Bound> bounds = new ArrayList<Bound>();
private Map<Long, Node> nodesById = new HashMap<Long, Node>();
private Map<Long, Way> waysById = new HashMap<Long, Way>();
private Map<Long, Relation> relationsById = new HashMap<Long, Relation>();
private Collection<OSMNode> ownNodes;
private Collection<OSMWay> ownWays;
private Collection<OSMRelation> ownRelations;
private final Sink sinkImplementation = new Sink() {
public void initialize(Map<String, Object> arg0) {
/* do nothing */
}
public void release() {
/* do nothing */
}
public void complete() {
setCompleteTrue();
}
public void process(EntityContainer entityContainer) {
Entity entity = entityContainer.getEntity();
if (entity instanceof Node) {
nodesById.put(entity.getId(), ((Node) entity));
} else if (entity instanceof Way) {
waysById.put(entity.getId(), ((Way) entity));
} else if (entity instanceof Relation) {
relationsById.put(entity.getId(), ((Relation) entity));
} else if (entity instanceof Bound) {
bounds.add((Bound) entity);
}
}
};
/*
* @param source
* a source providing the input data for the conversion
*/
protected OsmosisReader(RunnableSource source) {
this.source = source;
}
private void convertToOwnRepresentation() {
ownNodes = new ArrayList<OSMNode>(nodesById.size());
ownWays = new ArrayList<OSMWay>(waysById.size());
ownRelations = new ArrayList<OSMRelation>(relationsById.size());
Map<Node, OSMNode> nodeMap = new HashMap<Node, OSMNode>();
Map<Way, OSMWay> wayMap = new HashMap<Way, OSMWay>();
Map<Relation, OSMRelation> relationMap = new HashMap<Relation, OSMRelation>();
for (Node node : nodesById.values()) {
OSMNode ownNode = new OSMNode(node.getLatitude(), node
.getLongitude(), tagGroupForEntity(node), node.getId());
ownNodes.add(ownNode);
nodeMap.put(node, ownNode);
}
for (Way way : waysById.values()) {
List<WayNode> origWayNodes = way.getWayNodes();
List<OSMNode> wayNodes = new ArrayList<OSMNode>(origWayNodes.size());
for (WayNode origWayNode : origWayNodes) {
Node origNode = nodesById.get(origWayNode.getNodeId());
if (origNode != null) {
wayNodes.add(nodeMap.get(origNode));
}
}
OSMWay ownWay = new OSMWay(tagGroupForEntity(way),
way.getId(), wayNodes);
ownWays.add(ownWay);
wayMap.put(way, ownWay);
}
for (Relation relation : relationsById.values()) {
OSMRelation ownRelation = new OSMRelation(
tagGroupForEntity(relation), relation.getId(),
relation.getMembers().size());
ownRelations.add(ownRelation);
relationMap.put(relation, ownRelation);
}
// add relation members
// (needs to be done *after* creation because relations can be members
// of other relations)
for (Relation relation : relationMap.keySet()) {
OSMRelation ownRelation = relationMap.get(relation);
for (org.openstreetmap.osmosis.core.domain.v0_6.RelationMember member : relation
.getMembers()) {
OSMElement memberObject = null;
if (member.getMemberType() == EntityType.Node) {
memberObject = nodeMap.get(nodesById.get(member
.getMemberId()));
} else if (member.getMemberType() == EntityType.Way) {
memberObject = wayMap.get(waysById
.get(member.getMemberId()));
} else if (member.getMemberType() == EntityType.Relation) {
memberObject = relationMap.get(relationsById.get(member
.getMemberId()));
} else {
continue;
}
if (memberObject != null) {
OSMMember ownMember = new OSMMember(member
.getMemberRole(), memberObject);
ownRelation.relationMembers.add(ownMember);
}
}
}
// give up references to original collections
nodesById = null;
waysById = null;
relationsById = null;
}
private TagGroup tagGroupForEntity(Entity entity) {
if (entity.getTags().isEmpty()) {
return EMPTY_TAG_GROUP;
} else {
Map<String, String> tagMap = new HashMap<String, String>(entity.getTags().size());
for (Tag tag : entity.getTags()) {
tagMap.put(tag.getKey(), tag.getValue());
}
return new MapBasedTagGroup(tagMap);
}
}
@Override
public OSMData getData() throws IOException {
source.setSink(sinkImplementation);
Thread readerThread = new Thread(source);
readerThread.start();
while (readerThread.isAlive()) {
try {
readerThread.join();
} catch (InterruptedException e) { /* do nothing */
}
}
if (!isComplete()) {
throw new IOException("couldn't read from data source");
}
convertToOwnRepresentation();
return new OSMData(bounds, ownNodes, ownWays, ownRelations);
}
}