package org.androad.sys.ors.rs.cloudmade;
import java.util.ArrayList;
import org.osmdroid.util.BoundingBoxE6;
import org.osmdroid.util.GeoPoint;
import org.androad.R;
import org.androad.sys.ors.adt.Error;
import org.androad.sys.ors.adt.rs.Route;
import org.androad.sys.ors.adt.rs.RouteInstruction;
import org.androad.sys.ors.exceptions.ORSException;
import org.androad.util.constants.Constants;
import org.androad.util.constants.TimeConstants;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import android.util.Log;
public class CloudmadeRSParser extends DefaultHandler implements TimeConstants, Constants {
// ====================================
// Constants
// ====================================
// ====================================
// Fields
// ====================================
private final ArrayList<Error> mErrors = new ArrayList<Error>();
private int mErrorNumber = 0;
private Route mRoute;
private ArrayList<GeoPoint> mPolyline;
private double maxLat = 0;
private double maxLon = 0;
private double minLat = 0;
private double minLon = 0;
private boolean inGpx = false;
private boolean inExtensions = false;
private boolean inDistance = false;
private boolean inTime = false;
private boolean inStart = false;
private boolean inEnd = false;
private boolean inWpt = false;
private boolean inRte = false;
private boolean inRtept = false;
private boolean inDesc = false;
private boolean inOffset = false;
private boolean inDistanceText = false;
private boolean inDirection = false;
private boolean inAzimuth = false;
private RouteInstruction mTmpRouteInstruction;
// ===========================================================
// Constructors
// ===========================================================
public CloudmadeRSParser() {
}
// ===========================================================
// Getter & Setter
// ===========================================================
public ArrayList<Error> getErrors(){
return this.mErrors;
}
public Route getRoute() throws ORSException{
if(this.mErrors != null && this.mErrors.size() > 0) {
throw new ORSException(this.mErrors);
}
return this.mRoute;
}
// ====================================
// Methods from Superclasses
// ====================================
@Override
public void startDocument() throws SAXException {
this.mRoute = new Route();
this.mRoute.setRouteInstructions(new ArrayList<RouteInstruction>());
this.mPolyline = new ArrayList<GeoPoint>();
this.mRoute.setPolyLine(this.mPolyline);
super.startDocument();
}
@Override
public void startElement(final String uri, final String localName, final String name, final Attributes attributes) throws SAXException {
this.sb.setLength(0);
if(localName.equals("gpx")){
this.inGpx = true;
} else if(localName.equals("extensions")){
this.inExtensions = true;
} else if(localName.equals("distance")){
this.inDistance = true;
} else if(localName.equals("time")){
this.inTime = true;
} else if(localName.equals("start")){
this.inStart = true;
} else if(localName.equals("end")){
this.inEnd = true;
} else if(localName.equals("wpt")){
this.inWpt = true;
final double lat = Double.parseDouble(attributes.getValue("", "lat"));
final double lon = Double.parseDouble(attributes.getValue("", "lon"));
if (maxLat == 0 || lat > maxLat) {
maxLat = lat;
}
if (maxLon == 0 || lon > maxLon) {
maxLon = lon;
}
if (minLat == 0 || lat < minLat) {
minLat = lat;
}
if (minLon == 0 || lon < minLon) {
minLon = lon;
}
final GeoPoint geo = new GeoPoint(
(int) (lat * 1E6),
(int) (lon * 1E6));
this.mPolyline.add(geo);
} else if(localName.equals("rte")){
this.inRte = true;
} else if(localName.equals("rtept")){
this.inRtept = true;
final String lat = attributes.getValue("", "lat");
final String lon = attributes.getValue("", "lon");
final GeoPoint gp = new GeoPoint(
(int) (Double.parseDouble(lat) * 1E6),
(int) (Double.parseDouble(lon) * 1E6));
int first = this.mLastFirstMotherPolylineIndex + 1;
this.mLastFirstMotherPolylineIndex = this.mRoute.findInPolyLine(gp, this.mLastFirstMotherPolylineIndex);
for (;first < this.mLastFirstMotherPolylineIndex; first++) {
final GeoPoint geo = this.mPolyline.get(first);
this.mTmpRouteInstruction.getPartialPolyLine().add(geo);
}
this.mTmpRouteInstruction = new RouteInstruction();
this.mRoute.getRouteInstructions().add(this.mTmpRouteInstruction);
this.mTmpRouteInstruction.getPartialPolyLine().add(gp);
this.mTmpRouteInstruction.setFirstMotherPolylineIndex(this.mLastFirstMotherPolylineIndex);
} else if(localName.equals("desc")){
this.inDesc = true;
} else if(localName.equals("offset")){
this.inOffset = true;
} else if(localName.equals("distance-text")){
this.inDistanceText = true;
} else if(localName.equals("direction")){
this.inDirection = true;
} else if(localName.equals("azimuth")){
this.inAzimuth = true;
} else {
Log.w(DEBUGTAG, "Unexpected tag: '" + name + "'");
}
super.startElement(uri, localName, name, attributes);
}
protected StringBuilder sb = new StringBuilder();
private int mLastFirstMotherPolylineIndex = 0;
@Override
public void characters(final char[] chars, final int start, final int length) throws SAXException {
this.sb.append(chars, start, length);
super.characters(chars, start, length);
}
@Override
public void endElement(final String uri, final String localName, final String name) throws SAXException {
if(localName.equals("gpx")){
this.inGpx = false;
} else if(localName.equals("extensions")){
this.inExtensions = false;
} else if(localName.equals("distance")){
this.inDistance = false;
if (inExtensions) {
if (!inRte) {
this.mRoute.setDistanceMeters((int)Float.parseFloat(this.sb.toString()));
} else {
this.mTmpRouteInstruction.setLengthMeters((int)Float.parseFloat(this.sb.toString()));
}
}
} else if(localName.equals("time")){
this.inTime = false;
if (inExtensions) {
if (!inRte) {
this.mRoute.setDurationSeconds((int)Float.parseFloat(this.sb.toString()));
} else {
this.mTmpRouteInstruction.setDurationSeconds((int)Float.parseFloat(this.sb.toString()));
}
}
} else if(localName.equals("start")){
this.inStart = false;
} else if(localName.equals("end")){
this.inEnd = false;
} else if(localName.equals("wpt")){
this.inWpt = false;
} else if(localName.equals("rte")){
this.inRte = false;
} else if(localName.equals("rtept")){
this.inRtept = false;
} else if(localName.equals("desc")){
this.inDesc = false;
this.mTmpRouteInstruction.setDescriptionHtml(this.sb.toString());
} else if(localName.equals("offset")){
this.inOffset = false;
} else if(localName.equals("distance-text")){
this.inDistanceText = false;
} else if(localName.equals("direction")){
this.inDirection = false;
} else if(localName.equals("azimuth")){
this.inAzimuth = false;
} else {
Log.w(DEBUGTAG, "Unexpected end-tag: '" + name + "'");
}
// Reset the stringbuffer
this.sb.setLength(0);
super.endElement(uri, localName, name);
}
@Override
public void endDocument() throws SAXException {
if(this.mErrors == null || this.mErrors.size() == 0){
int first = this.mLastFirstMotherPolylineIndex + 1;
for (;first < this.mPolyline.size(); first++) {
final GeoPoint geo = this.mPolyline.get(first);
this.mTmpRouteInstruction.getPartialPolyLine().add(geo);
}
this.mRoute.setBoundingBoxE6(new BoundingBoxE6(maxLat, maxLon, minLat, minLon));
this.mRoute.setStart(this.mPolyline.get(0));
this.mRoute.setDestination(this.mPolyline.get(this.mPolyline.size() - 1));
this.mRoute.setStartInstruction(this.mRoute.getRouteInstructions().remove(0));
// Modify the arrival-instruction that is just shows
final RouteInstruction last = this.mRoute.getRouteInstructions().get(this.mRoute.getRouteInstructions().size() - 1);
last.setFirstMotherPolylineIndex(this.mPolyline.size() - 1);
}
super.endDocument();
}
}