package com.schneeloch.bostonbusmap_library.data; import java.io.IOException; import java.util.Calendar; import java.util.Collection; import java.util.List; import java.util.Map; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.schneeloch.bostonbusmap_library.database.Schema; import com.schneeloch.bostonbusmap_library.math.Geometry; import com.schneeloch.bostonbusmap_library.transit.TransitSource; import com.schneeloch.bostonbusmap_library.transit.TransitSystem; import com.schneeloch.bostonbusmap_library.util.Box; import com.schneeloch.bostonbusmap_library.util.IBox; public class RouteConfig { private final StopFacade stopFacade; private Path[] paths; private final String route; private final String routeTitle; private final int listorder; private final Schema.Routes.SourceId transitSourceId; private final int color; private final int oppositeColor; private final TransitSource transitSource; public static final Path[] nullPaths = new Path[0]; private final TimeBounds timeBounds; private RouteConfig(Builder builder, ImmutableMap<String, StopLocation> stops) throws IOException { this.route = builder.route; this.routeTitle = builder.routeTitle; this.stopFacade = new StopFacade(stops); this.color = builder.color; this.oppositeColor = builder.oppositeColor; this.transitSource = builder.transitSource; if (builder.serializedPath.isEmpty() == false) { paths = builder.serializedPath.readPathsList(color); } else { paths = nullPaths; } this.listorder = builder.listorder; this.transitSourceId = builder.transitSourceId; this.timeBounds = builder.timeBounds.build(routeTitle); } private RouteConfig(Builder builder) throws IOException { this(builder, ImmutableMap.copyOf(builder.stops)); } public static class Builder { private final String route; private final String routeTitle; private final int color; private final int oppositeColor; private final TransitSource transitSource; private final IBox serializedPath; private final Map<String, StopLocation> stops = Maps.newHashMap(); private final List<Path> paths = Lists.newArrayList(); private final int listorder; private final Schema.Routes.SourceId transitSourceId; private final TimeBounds.Builder timeBounds = TimeBounds.builder(); public Builder(String route, String routeTitle, int color, int oppositeColor, TransitSource transitSource, int listorder, Schema.Routes.SourceId transitSourceId) { this(route, routeTitle, color, oppositeColor, transitSource, listorder, transitSourceId, Box.emptyBox()); } public Builder(String route, String routeTitle, int color, int oppositeColor, TransitSource transitSource, int listorder, Schema.Routes.SourceId transitSourceId, IBox serializedPath) { this.route = route; this.routeTitle = routeTitle; this.color = color; this.oppositeColor = oppositeColor; this.transitSource = transitSource; this.serializedPath = serializedPath; this.listorder = listorder; this.transitSourceId = transitSourceId; } public StopLocation getStop(String tag) { return stops.get(tag); } public void addStop(String stopTag, StopLocation stopLocation) { stops.put(stopTag, stopLocation); } public void addPaths(Path path) { paths.add(path); } public void addTimeBound(int weekdaysBits, int start, int end) { timeBounds.add(weekdaysBits, start, end); } public String getRouteName() { return route; } public String getRouteTitle() { return routeTitle; } public int getColor() { return color; } public int getOppositeColor() { return oppositeColor; } public RouteConfig build() throws IOException { return new RouteConfig(this); } public RouteConfig build(ImmutableMap<String, StopLocation> stops) throws IOException { return new RouteConfig(this, stops); } public boolean containsStop(String stopTag) { return stops.containsKey(stopTag); } } public StopLocation getStop(String tag) { return stopFacade.getStops().get(tag); } public ImmutableMap<String, StopLocation> getStopMapping() { return stopFacade.getStops(); } public Collection<StopLocation> getStops() { return stopFacade.getStops().values(); } public void replaceStops(ImmutableMap<String, StopLocation> newStops) { stopFacade.replaceStops(newStops); } public String getRouteName() { return route; } public String getRouteTitle() { return routeTitle; } public Path[] getPaths() { return paths; } public int getColor() { return color; } public void serializePath(IBox dest) throws IOException { dest.writePathsList(paths); } public TransitSource getTransitSource() { return transitSource; } public boolean hasPaths() { return transitSource.hasPaths(); } public int getOppositeColor() { return oppositeColor; } public void setPaths(Path[] paths) { this.paths = paths; } /** * For efficiency's sake this should be called sparingly * @param path */ public void addPaths(Path path) { Path[] paths = new Path[this.paths.length + 1]; for (int i = 0; i < this.paths.length; i++) { paths[i] = this.paths[i]; } paths[this.paths.length] = path; this.paths = paths; } /** * Find what stop has the same location as the given stop * @param stop * @return */ public String getCrossStopTag(StopLocation otherStop, List<String> stopTagsToChooseFrom) { float minDistance = 9999999; StopLocation candidate = null; for (String stopTag : stopTagsToChooseFrom) { StopLocation stop = stopFacade.getStops().get(stopTag); float distance = Geometry.computeCompareDistance(stop.getLatitudeAsDegrees(), stop.getLongitudeAsDegrees(), otherStop.getLatitudeAsDegrees(), otherStop.getLongitudeAsDegrees()); if (distance < minDistance) { candidate = stop; minDistance = distance; } } return candidate.getStopTag(); } public Schema.Routes.SourceId getTransitSourceId() { return transitSourceId; } public int getListOrder() { return listorder; } public boolean isRouteRunning() { Calendar calendar = Calendar.getInstance(TransitSystem.getTimeZone()); return timeBounds.isRouteRunning(calendar); } public TimeBounds getTimeBounds() { return timeBounds; } public IAlerts getAlerts() { return transitSource.getAlerts(); } }