/*!
* A train transfer guide.
*
* Copyright (C) 2023-2024 kaoru
*/
mod timetable;
use std::collections::HashSet;
use std::env;
use std::fs::File;
use std::io::{stdin, stdout, BufRead, BufReader, Lines, StdinLock, Write};
use std::path::Path;
use std::process::exit;
use anyhow::Result;
use unicode_width::UnicodeWidthStr;
use tetengo_lattice::{Constraint, Lattice, NBestIterator, Node, StringInput};
use crate::timetable::{Section, Timetable};
fn main() {
if let Err(e) = main_core() {
eprintln!("Error: {}", e);
exit(1);
}
}
fn main_core() -> Result<()> {
let args = env::args().collect::>();
if args.len() <= 1 {
eprintln!("Usage: transfer_trains timetable.txt");
return Ok(());
}
let timetable = Timetable::new(create_reader(Path::new(&args[1]))?)?;
let mut lines = stdin().lines();
loop {
let departure_and_arrival = match get_departure_and_arrival(&mut lines, &timetable)? {
Input::DepartureAndArrival(Some(value)) => value,
Input::DepartureAndArrival(None) => continue,
Input::Eof => break,
};
let ((_, departure_time), _) = departure_and_arrival;
let vocabulary = timetable.create_vocabulary(departure_time);
let mut lattice = Lattice::new(vocabulary.as_ref());
build_lattice(departure_and_arrival, &timetable, &mut lattice)?;
let eos_node = lattice.settle()?;
let trips = enumerate_trips(&lattice, eos_node, 5);
print_trips(&trips, &timetable);
}
Ok(())
}
fn create_reader(path: &Path) -> Result> {
let reader = BufReader::new(File::open(path)?);
Ok(Box::new(reader))
}
enum Input {
DepartureAndArrival(Option<((usize, usize), usize)>),
Eof,
}
fn get_departure_and_arrival(
lines: &mut Lines>,
timetable: &Timetable,
) -> Result {
let Some(departure_station_index) = get_station_index("Departure Station", lines, timetable)?
else {
return Ok(Input::Eof);
};
if departure_station_index >= timetable.stations().len() {
println!("No departure station is found.");
return Ok(Input::DepartureAndArrival(None));
}
let Some(departure_time) = get_time("Departure Time", lines)? else {
return Ok(Input::Eof);
};
if departure_time >= 1440 {
println!("Wrong time format.");
return Ok(Input::DepartureAndArrival(None));
}
let Some(arrival_station_index) = get_station_index("Arrival Station", lines, timetable)?
else {
return Ok(Input::Eof);
};
if arrival_station_index >= timetable.stations().len() {
println!("No arrival station is found.");
return Ok(Input::DepartureAndArrival(None));
};
Ok(Input::DepartureAndArrival(Some((
(departure_station_index, departure_time),
arrival_station_index,
))))
}
fn get_station_index(
prompt: &str,
lines: &mut Lines>,
timetable: &Timetable,
) -> Result