public (BusSystemData data, List <string> errors) LoadTransitData() { var connexionzPlatforms = ConnexionzClient.LoadPlatforms(); var connexionzRoutes = ConnexionzClient.LoadRoutes(); var googleData = GoogleTransitClient.LoadData(); var routes = CreateRoutes(googleData.Routes, connexionzRoutes); var stops = CreateStops(connexionzPlatforms, connexionzRoutes); var staticData = new BusStaticData( routes: routes.ToDictionary(r => r.RouteNo), stops: stops.ToDictionary(s => s.Id) ); var platformTagsLookup = connexionzPlatforms.ToDictionary(p => p.PlatformNo, p => p.PlatformTag); var schedule = CreateSchedule(googleData.Schedules, connexionzRoutes, connexionzPlatforms); var transitData = new BusSystemData( staticData, schedule, platformTagsLookup); var errors = ValidateTransitData(transitData); return(transitData, errors); }
public static List <string> ValidateTransitData(BusSystemData data) { var errors = new List <string>(); // Validate schedule within each stop foreach (var kvp in data.Schedule) { var(stopId, stopRouteSchedules) = (kvp.Key, kvp.Value); foreach (var routeSchedule in stopRouteSchedules) { foreach (var routeDaySchedule in routeSchedule.DaySchedules) { if (routeDaySchedule.Days == DaysOfWeek.None) { errors.Add($"Route {routeSchedule.RouteNo} at stop {stopId} has a day schedule for DaysOfWeek.None."); } var currentTime = TimeSpan.MinValue; foreach (var nextTime in routeDaySchedule.Times) { if (nextTime <= currentTime) { errors.Add($"Route {routeSchedule.RouteNo} at stop {stopId} has an ordering discrepancy in its schedule. Arrival time {currentTime} is followed by {nextTime}"); } currentTime = nextTime; } } } } // Validate schedule for each route foreach (var route in data.StaticData.Routes.Values) { var firstStopId = route.Path[0]; var firstStopSchedules = data.Schedule[firstStopId].FirstOrDefault(rs => rs.RouteNo == route.RouteNo); if (firstStopSchedules == null) { errors.Add($"Route {route.RouteNo} has no schedule for stop ID {firstStopId}"); continue; } foreach (var firstStopDaySchedule in firstStopSchedules.DaySchedules) { for (var arrivalNo = 0; arrivalNo < firstStopDaySchedule.Times.Count; arrivalNo++) { // get the i'th arrival for each stop in the path, ensure monotonically increasing var currentArrivalTime = TimeSpan.MinValue; for (var stopIdx = 0; stopIdx < route.Path.Count; stopIdx++) { var stopId = route.Path[stopIdx]; if (stopId == 0) { errors.Add($"Route {route.RouteNo} has a missing stop in its path at index {stopIdx}"); continue; } else if (stopId < 1000) { errors.Add($"Route {route.RouteNo} is using platform tag {stopId} as an ID because it has no stop ID"); continue; } else if (!data.Schedule.ContainsKey(stopId)) { errors.Add($"Route {route.RouteNo} is using stop ID {stopId} which has no schedule"); continue; } var routeStopDayArrivalTimes = data .Schedule[stopId] .Single(rs => rs.RouteNo == route.RouteNo) .DaySchedules .Single(ds => ds.Days == firstStopDaySchedule.Days) .Times; var nextArrivalTime = routeStopDayArrivalTimes[arrivalNo]; if (nextArrivalTime <= currentArrivalTime) { Debug.Assert(stopIdx > 0); errors.Add($"Route {route.RouteNo} has a schedule discrepancy across stops {route.Path[stopIdx - 1]} and {route.Path[stopIdx]}. Arrival time {currentArrivalTime} is followed by {nextArrivalTime}"); } currentArrivalTime = nextArrivalTime; } } } } return(errors.Distinct().ToList()); }