/**
* Created by Nicholas Hallahan on 12/24/14.
* nhallahan@spatialdev.com
*/
package com.spatialdev.osm.model;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.codec.digest.DigestUtils;
import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
public class OSMRelation extends OSMElement {
// These are the members that refer to another OSM Element.
private class RelationMember {
public Long ref;
public String type;
public String role;
public OSMElement linkedElement;
public RelationMember(Long ref, String type, String role) {
this.ref = ref;
this.type = type;
this.role = role;
}
}
private LinkedList<RelationMember> nodeMembers = new LinkedList<>();
private LinkedList<RelationMember> wayMembers = new LinkedList<>();
private LinkedList<RelationMember> relationMembers = new LinkedList<>();
private LinkedList<OSMNode> linkedNodes = new LinkedList<>();
private LinkedList<OSMWay> linkedWays = new LinkedList<>();
private LinkedList<OSMRelation> linkedRelations = new LinkedList<>();
private int unlinkedMembersCount = 0;
public OSMRelation(String idStr,
String versionStr,
String timestampStr,
String changesetStr,
String uidStr,
String userStr,
String action) {
super(idStr, versionStr, timestampStr, changesetStr, uidStr, userStr, action);
}
@Override
public String checksum() {
StringBuilder str = tagsAsSortedKVString();
for (OSMNode n : linkedNodes) {
str.append(n.checksum());
}
for (OSMWay w : linkedWays) {
str.append(w.checksum());
}
for (OSMRelation r : linkedRelations) {
str.append(r.checksum());
}
return new String(Hex.encodeHex(DigestUtils.sha1(str.toString())));
}
@Override
void xml(XmlSerializer xmlSerializer, String omkOsmUser) throws IOException {
xmlSerializer.startTag(null, "relation");
if (isModified()) {
xmlSerializer.attribute(null, "action", "modify");
}
setOsmElementXmlAttributes(xmlSerializer, omkOsmUser);
// generate members
setRelationXmlMembers(xmlSerializer);
// generate tags
super.xml(xmlSerializer, omkOsmUser);
xmlSerializer.endTag(null, "relation");
}
private void setRelationXmlMembers(XmlSerializer xmlSerializer) throws IOException {
for (RelationMember mem: nodeMembers) {
writeXmlMember(mem, xmlSerializer);
}
for (RelationMember mem: wayMembers) {
writeXmlMember(mem, xmlSerializer);
}
for (RelationMember mem: relationMembers) {
writeXmlMember(mem, xmlSerializer);
}
}
private void writeXmlMember(RelationMember mem, XmlSerializer xmlSerializer) throws IOException {
xmlSerializer.startTag(null, "member");
xmlSerializer.attribute(null, "type", mem.type);
xmlSerializer.attribute(null, "ref", String.valueOf(mem.ref));
xmlSerializer.attribute(null, "role", mem.role);
xmlSerializer.endTag(null, "member");
}
public void addNodeRef(long id, String role) {
nodeMembers.add(new RelationMember(id, "node", role));
}
public void addWayRef(long id, String role) {
wayMembers.add(new RelationMember(id, "way", role));
}
public void addRelationRef(long id, String role) {
relationMembers.add(new RelationMember(id, "relation", role));
}
int link(Map<Long, OSMNode> nodes, Map<Long, OSMWay> ways, Map<Long, OSMRelation> relations) {
int unlinkedNodes = linkNodes(nodes);
int unlinkedWays = linkWays(ways);
int unlinkedRelations = linkRelations(relations);
unlinkedMembersCount = unlinkedNodes + unlinkedWays + unlinkedRelations;
return unlinkedMembersCount;
}
private int linkNodes(Map<Long, OSMNode> nodes) {
int unlinkedCount = 0;
for (RelationMember mem : nodeMembers) {
OSMNode node = nodes.get(mem.ref);
if (node == null) {
++unlinkedCount;
} else {
node.addRelation(this);
mem.linkedElement = node;
linkedNodes.push(node);
}
}
return unlinkedCount;
}
private int linkWays(Map<Long, OSMWay> ways) {
int unlinkedCount = 0;
for (RelationMember mem : wayMembers) {
OSMWay way = ways.get(mem.ref);
if (way == null) {
++unlinkedCount;
} else {
way.addRelation(this);
mem.linkedElement = way;
linkedWays.push(way);
}
}
return unlinkedCount;
}
private int linkRelations(Map<Long, OSMRelation> relations) {
int unlinkedCount = 0;
for (RelationMember mem: relationMembers) {
OSMRelation rel = relations.get(mem.ref);
if (rel == null) {
++unlinkedCount;
} else {
rel.addRelation(this);
mem.linkedElement = rel;
linkedRelations.push(rel);
}
}
return unlinkedCount;
}
public void addRelation(OSMRelation relation) {
linkedRelations.push(relation);
}
public List<OSMRelation> getRelations() {
return linkedRelations;
}
public int getUnlinkedMemberCount() {
return unlinkedMembersCount;
}
}