package com.schneeloch.bostonbusmap_library.parser; import java.io.IOException; import java.io.InputStream; import java.util.Map; import javax.xml.parsers.ParserConfigurationException; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; import com.google.common.collect.Maps; import android.util.Xml.Encoding; import com.schneeloch.bostonbusmap_library.data.Directions; import com.schneeloch.bostonbusmap_library.data.TimePrediction; import com.schneeloch.bostonbusmap_library.data.RouteConfig; import com.schneeloch.bostonbusmap_library.data.RoutePool; import com.schneeloch.bostonbusmap_library.data.StopLocation; import com.schneeloch.bostonbusmap_library.util.LogUtil; import com.schneeloch.bostonbusmap_library.util.StringUtil; public class BusPredictionsFeedParser extends DefaultHandler { private static final String stopTagKey = "stopTag"; private static final String minutesKey = "minutes"; private static final String epochTimeKey = "epochTime"; private static final String vehicleKey = "vehicle"; private static final String affectedByLayoverKey = "affectedByLayover"; private static final String dirTagKey = "dirTag"; private static final String predictionKey = "prediction"; private static final String directionKey = "direction"; private static final String predictionsKey = "predictions"; private static final String routeTagKey = "routeTag"; private static final String delayedKey = "delayed"; private static final String titleKey = "title"; private static final String blockKey = "block"; private final RoutePool stopMapping; private StopLocation currentLocation; private RouteConfig currentRoute; private final Directions directions; private String directionTitle; private final long currentTimeMillis; private final Map<String, Integer> tagCache = Maps.newHashMap(); public BusPredictionsFeedParser(RoutePool stopMapping, Directions directions) { this.stopMapping = stopMapping; this.directions = directions; this.currentTimeMillis = System.currentTimeMillis(); } public void runParse(InputStream data) throws ParserConfigurationException, SAXException, IOException { android.util.Xml.parse(data, Encoding.UTF_8, this); data.close(); } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if (localName.equals(predictionsKey)) { String currentRouteTag = attributes.getValue(routeTagKey); try { currentRoute = stopMapping.get(currentRouteTag); } catch (IOException e) { LogUtil.e(e); currentRoute = null; } currentLocation = null; if (currentRoute != null) { String stopTag = attributes.getValue(stopTagKey); currentLocation = currentRoute.getStop(stopTag); if (currentLocation != null) { currentLocation.clearPredictions(currentRoute); } } } else if (localName.equals(directionKey)) { clearAttributes(attributes); directionTitle = getAttribute(titleKey, attributes); } else if (localName.equals(predictionKey)) { clearAttributes(attributes); if (currentLocation != null && currentRoute != null) { int minutes = Integer.parseInt(getAttribute(minutesKey, attributes)); long epochTime = Long.parseLong(getAttribute(epochTimeKey, attributes)); String vehicleId = getAttribute(vehicleKey, attributes); boolean affectedByLayover = Boolean.parseBoolean(getAttribute(affectedByLayoverKey, attributes)); boolean isDelayed = Boolean.parseBoolean(getAttribute(delayedKey, attributes)); String dirTag = getAttribute(dirTagKey, attributes); String block = getAttribute(blockKey, attributes); String directionSnippet = directions.getTitleAndName(dirTag); if (StringUtil.isEmpty(directionSnippet)) { directionSnippet = directionTitle; } long arrivalTimeMillis = currentTimeMillis + minutes * 60 * 1000; TimePrediction prediction = new TimePrediction(arrivalTimeMillis, vehicleId, directionSnippet, currentRoute.getRouteName(), currentRoute.getRouteTitle(), affectedByLayover, isDelayed, TimePrediction.NULL_LATENESS, block, currentLocation.getStopTag()); currentLocation.addPrediction(prediction); } } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { if (localName.equals(directionKey)) { directionTitle = null; } } private String getAttribute(String key, Attributes attributes) { return XmlParserHelper.getAttribute(key, attributes, tagCache); } private void clearAttributes(Attributes attributes) { XmlParserHelper.clearAttributes(attributes, tagCache); } }