use actix_web::{get, web::{self, Data}, HttpRequest, HttpResponse, Responder}; use anyhow::anyhow; use std::{collections::{HashMap, HashSet}, sync::Arc, time::Instant}; use libseptastic::{direction, route::RouteType, stop_schedule::Trip}; use serde::{Serialize, Deserialize}; use crate::AppState; //use crate::{routing::{bfs_rts, construct_graph, get_stops_near}, AppState}; //use crate::routing; #[get("/routes")] async fn get_routes_html(req: HttpRequest, state: Data>) -> impl Responder { crate::perform_action(req, move || { let statex = state.clone(); async move { let start_time = Instant::now(); let all_routes: Vec = statex.gtfs_service.get_routes(); let rr_routes = all_routes.clone().into_iter().filter(|x| x.route_type == RouteType::RegionalRail).collect(); let subway_routes = all_routes.clone().into_iter().filter(|x| x.route_type == RouteType::SubwayElevated).collect(); let trolley_routes = all_routes.clone().into_iter().filter(|x| x.route_type == RouteType::Trolley).collect(); let bus_routes = all_routes.into_iter().filter(|x| x.route_type == RouteType::TracklessTrolley || x.route_type == RouteType::Bus).collect(); Ok(crate::templates::ContentTemplate { page_title: Some(String::from("Routes")), page_desc: Some(String::from("All SEPTA routes.")), widescreen: false, content: crate::templates::RoutesTemplate { rr_routes, subway_routes, trolley_routes, bus_routes, }, load_time_ms: Some(start_time.elapsed().as_millis()) }) } }).await } #[get("/routes.json")] async fn get_routes_json(state: Data>) -> impl Responder { let all_routes: Vec = state.gtfs_service.get_routes(); HttpResponse::Ok().json(all_routes) } #[derive(Debug, Deserialize, Clone)] pub struct RouteQueryParams { #[serde(default)] // Optional: handle missing parameters with a default value stops: Option, } #[derive(Serialize, Deserialize)] pub struct RouteResponse { pub route: libseptastic::route::Route, pub directions: Vec, pub schedule: Vec } async fn get_route_info(route_id: String, state: Data>) -> ::anyhow::Result { let route = state.gtfs_service.get_route(route_id.clone())?; let mut trips = state.gtfs_service.get_schedule(route_id)?; let mut seen = HashSet::new(); let directions: Vec<_> = trips .iter() .map(|x| x.direction.clone()) .filter(|dir| seen.insert(dir.direction.to_string())) .collect(); state.trip_tracking_service.annotate_trips(&mut trips).await; Ok(RouteResponse{ route, directions, schedule: trips }) } //#[get("/directions")] //async fn get_directions(state: Data>) -> impl Responder { // let near_thresh = 0.45; // // let sig_cds = routing::Coordinates { // lat: 40.008420, // lng: -75.213439 // }; // // let home_cds = routing::Coordinates { // lat: 39.957210, // lng: -75.166214 // }; // // let all_stops = state.gtfs_service.get_all_stops(); // // // // let origin_stops: HashSet = get_stops_near(home_cds, &all_stops); // let dest_stops: HashSet = get_stops_near(sig_cds.clone(), &all_stops); // // let mut graph = construct_graph(sig_cds, &all_stops, &state.gtfs_service); // // let mut response = String::new(); // for stop in &origin_stops { // response += bfs_rts(&stop, &mut graph, &dest_stops).as_str(); // } // // return response; //} #[get("/route/{route_id}")] async fn get_route(state: Data>, req: HttpRequest, info: web::Query, path: web::Path) -> impl Responder { crate::perform_action(req, move || { let pathx = path.clone(); let infox = info.clone(); let statex = state.clone(); async move { let mut filters: Option> = None; if let Some (stops_v) = infox.stops.clone() { let mut items = Vec::new(); for sid in stops_v.split(",") { items.push(String::from(sid)); } filters = Some(items); } let route_id = pathx; let route_info_r = get_route_info(route_id.clone(), statex.clone()).await; if let Ok(route_info) = route_info_r { let timetables = crate::templates::build_timetables(route_info.directions, route_info.schedule); Ok(crate::templates::ContentTemplate { widescreen: false, page_title: Some(format!("Schedules for {}", route_id.clone())), page_desc: Some(format!("Schedule information for {}", route_id.clone())), content: crate::templates::RouteTemplate { route: route_info.route, timetables, filter_stops: filters.clone() }, load_time_ms: None }) } else { Err(anyhow!("test")) } }}).await } #[get("/route/{route_id}.json")] async fn api_get_route(state: Data>, path: web::Path) -> impl Responder { let route_id = path.into_inner(); let route_info_r = get_route_info(route_id, state).await; if let Ok(route_info) = route_info_r { HttpResponse::Ok().json(route_info) } else { HttpResponse::InternalServerError().body("Error") } } #[get("/api/route/{route_id}/schedule")] async fn api_get_schedule(state: Data>, path: web::Path) -> impl Responder { let route_id = path.into_inner(); let route_r: anyhow::Result = Ok(5); if let Ok(route) = route_r { HttpResponse::Ok().json(route) } else { HttpResponse::InternalServerError().body("Error") } }