1#![doc = include_str!("../README.md")]
42
43pub mod station;
44pub mod cab;
45pub mod train;
46pub mod primio;
47
48use crate::station::*;
49use crate::cab::*;
50use crate::train::*;
51use crate::primio::*;
52use std::collections::HashMap;
53use std::collections::LinkedList;
57use std::path::PathBuf;
58use std::str::FromStr;
59use std::convert::Infallible;
60use std::fs::File;
61use std::io::prelude::*;
62use std::io::{Write,BufReader,BufWriter};
63use std::fmt;
64
65
66pub type DoubleVector = Vec<f64>;
73
74pub type OptionHashMap = HashMap<String, String>;
80
81
82pub type TrainList<'latex> = Vec<&'latex Train>;
90
91#[derive(Debug, Clone, Copy, PartialEq)]
109pub struct StationTimes {
110 arrival: f64,
111 departure: f64,
112 flag: StopFlagType,
113}
114
115impl Default for StationTimes {
116 fn default() -> Self {
117 Self {arrival: -1.0, departure: -1.0, flag: StopFlagType::Transit}
118 }
119}
120
121
122impl StationTimes {
123 pub fn new(a: f64, d: f64, f: StopFlagType) -> Self {
130 Self {arrival: a, departure: d, flag: f }
131 }
132 pub fn Arrival(&self) -> f64 {self.arrival}
135 pub fn Departure(&self) -> f64 {self.departure}
138 pub fn Flag(&self) -> StopFlagType {self.flag}
141
142}
143
144pub type TrainStationTimes = HashMap<String,StationTimes>;
155
156pub type TrainTimesAtStation = HashMap<usize, TrainStationTimes>;
166
167pub type StringList = LinkedList<String>;
174
175pub fn StringListToString(list: StringList) -> String {
187 let mut result: String = String::new();
188 let mut comma: String = String::new();
189 for theString in list.iter() {
190 result += ,
191 result += "\"";
192 for char in theString.chars() {
193 if char == '"' || char == '\\' {result += "\\";}
194 result += &String::from(char);
195 }
196 result += "\"";
197 comma = String::from(",");
198 }
199 result
200}
201
202pub fn StringListFromString(strlinList: String) -> Option<StringList> {
212 let mut result = LinkedList::new();
213 let mut inString: bool = false;
214 let mut expectcomma: bool = false;
215 let mut expectquotes: bool = true;
216 let mut escape: bool= false;
217 let mut theString: String = String::new();
218 for c in strlinList.chars() {
219 if inString {
220 if escape {
221 theString += &String::from(c);
222 escape = false;
223 } else if c == '"' {
224 result.push_back(theString.clone());
225 theString.clear();
226 inString = false;
227 expectcomma = true;
228 expectquotes = false;
229 } else if c == '\\' {
230 escape = true;
231 } else {
232 theString += &String::from(c);
233 }
234 } else {
235 if c == ',' && expectcomma {
236 expectcomma = false;
237 expectquotes = true;
238 } else if c == '"' && expectquotes {
239 theString.clear();
240 inString = true;
241 } else {
242 return None
243 }
244 }
245 }
246 if escape {
247 None
248 } else if result.len() == 0 && !inString && expectquotes {
249 Some(result)
250 } else if !inString && expectcomma {
251 Some(result)
252 } else {
253 None
254 }
255}
256
257#[derive(Debug, Clone, PartialEq)]
271pub struct TimeTableSystem {
272 name: String,
273 filepath: PathBuf,
274 timescale: u32,
275 timeinterval: u32,
276 stations: StationVector,
277 cabs: CabNameMap,
278 trains: TrainNumberMap,
279 notes: Vec<String>,
280 print_options: OptionHashMap,
281 table_of_contents_p: bool,
282 direction_name: String,
283}
284
285#[derive(Debug, Clone, PartialEq)]
286pub enum ConstructorError {
287 BadFilename(Infallible),
288 CouldNotOpenFile(String,String),
289 PrematureEOF(String),
290 FileIOError(String,String),
291 }
304
305impl fmt::Display for ConstructorError {
306 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
307 match self {
308 Self::BadFilename(patherr) => write!(f, "Pathname error: {}",patherr),
309 Self::CouldNotOpenFile(filename,error) =>
310 write!(f, "Cound not open file {}: {}",filename,error),
311 Self::PrematureEOF(where_) =>
312 write!(f, "Premature EOF {}",where_),
313 Self::FileIOError(where_,error) =>
314 write!(f, "File I/O Error: {}: {}",where_,error),
315 }
330 }
331}
332
333#[derive(Debug, Clone, PartialEq)]
334pub enum AddTrainError {
335 EmptyStopList,
336 DuplicateTrain,
337 RangeError(String),
338 BadStationNumber(usize),
339 DuplicateStorageIsAt(String,String,String),
340 DuplicateStorageAt(String,String),
341
342}
343
344#[derive(Debug, Clone, PartialEq)]
345pub enum DeleteTrainError {
346 NoSuchTrain(String),
347 InternalMissingOcc(String),
348}
349
350#[derive(Debug)]
351pub enum CreateLaTeXError {
352 NoTrainsError,
353 FileIOError(std::io::Error),
354 GroupSyntaxError(u32),
355 GroupEmpty(u32),
356
357}
358
359impl From<std::io::Error> for CreateLaTeXError {
360 fn from(error: std::io::Error) -> Self {
361 CreateLaTeXError::FileIOError(error)
362 }
363}
364
365#[derive(Debug, Clone, PartialEq)]
366pub enum GroupMode {
367 NoGrouping,
368 Class,
369}
370impl TimeTableSystem {
371 pub fn old(filename: &str) -> Result<Self, ConstructorError> {
380 let filepath: PathBuf = match PathBuf::from_str(filename) {
381 Ok(f) => f,
382 Err(p) => return Err(ConstructorError::BadFilename(p)),
383 };
384 let file = match File::open(&filepath) {
385 Ok(f) => f,
386 Err(e) => return Err(ConstructorError::CouldNotOpenFile(
387 filename.to_string(),
388 e.to_string())),
389 };
390 let mut buf_reader = BufReader::new(file);
391 let mut name: String = String::new();
392 match buf_reader.read_line(&mut name) {
393 Ok(l) => if l == 0 {
394 return Err(ConstructorError::PrematureEOF(String::from("Reading name")));
395 },
396 Err(e) => return Err(ConstructorError::FileIOError(String::from("Reading name"),e.to_string())),
397 };
398 name = name.trim().to_string();
399 let timescale: u32 = match ReadU32(&mut buf_reader) {
400 Err(e) => return Err(ConstructorError::FileIOError(String::from("Reading Timescale"),e.to_string())),
401 Ok(None) => return Err(ConstructorError::PrematureEOF(String::from("Reading Timescale"))),
402 Ok(Some(s)) => s,
403 };
404 let timeinterval: u32 = match ReadU32(&mut buf_reader) {
405 Err(e) => return Err(ConstructorError::FileIOError(String::from("Reading Timeinterval"),e.to_string())),
406 Ok(None) => return Err(ConstructorError::PrematureEOF(String::from("Reading Timeinterval"))),
407 Ok(Some(s)) => s,
408 };
409 let mut this = Self {name: name, filepath: filepath,
410 timescale: timescale, timeinterval: timeinterval,
411 stations: Vec::new(), cabs: HashMap::new(),
412 trains: HashMap::new(), notes: Vec::new(),
413 print_options: HashMap::new(),
414 table_of_contents_p: true,
415 direction_name: String::new() };
416 let mut count: usize = match ReadUSize(&mut buf_reader) {
417 Err(e) => return Err(ConstructorError::FileIOError(String::from("Reading Station count"),e.to_string())),
418 Ok(None) => return Err(ConstructorError::PrematureEOF(String::from("Reading Station count"))),
419 Ok(Some(s)) => s,
420 };
421 for i in 0..count {
422 let station = match Station::Read(&mut buf_reader) {
423 Err(e) => return Err(ConstructorError::FileIOError(String::from("Reading Station"),e.to_string())),
424 Ok(None) => return Err(ConstructorError::PrematureEOF(String::from("Reading Station"))),
425 Ok(Some(s)) => s,
426 };
427 this.stations.push(station);
428 }
429 count = match ReadUSize(&mut buf_reader) {
430 Err(e) => return Err(ConstructorError::FileIOError(String::from("Reading Cab count"),e.to_string())),
431 Ok(None) => return Err(ConstructorError::PrematureEOF(String::from("Reading Cab count"))),
432 Ok(Some(s)) => s,
433 };
434 for i in 0..count {
435 let cab = match Cab::Read(&mut buf_reader) {
436 Err(e) => return Err(ConstructorError::FileIOError(String::from("Reading Cab"),e.to_string())),
437 Ok(None) => return Err(ConstructorError::PrematureEOF(String::from("Reading Cab"))),
438 Ok(Some(c)) => c,
439 };
440 this.cabs.insert(cab.Name().clone(),cab);
441 }
442 count = match ReadUSize(&mut buf_reader) {
443 Err(e) => return Err(ConstructorError::FileIOError(String::from("Reading Train count"),e.to_string())),
444 Ok(None) => return Err(ConstructorError::PrematureEOF(String::from("Reading Train count"))),
445 Ok(Some(s)) => s,
446 };
447 for i in 0..count {
448 let train = match Train::Read(&mut buf_reader,&this.cabs) {
449 Err(e) => return Err(ConstructorError::FileIOError(String::from("Reading Train"),e.to_string())),
450 Ok(None) => return Err(ConstructorError::PrematureEOF(String::from("Reading Train"))),
451 Ok(Some(t)) => t,
452 };
453 this.trains.insert(train.Number(),train);
454 }
455 count = match ReadUSize(&mut buf_reader) {
456 Err(e) => return Err(ConstructorError::FileIOError(String::from("Reading Note count"),e.to_string())),
457 Ok(None) => return Err(ConstructorError::PrematureEOF(String::from("Reading Note count"))),
458 Ok(Some(s)) => s,
459 };
460 for i in 0..count {
461 let note = match Self::ReadNote(&mut buf_reader) {
462 Err(e) => return Err(ConstructorError::FileIOError(String::from("Reading Note"),e.to_string())),
463 Ok(None) => return Err(ConstructorError::PrematureEOF(String::from("Reading Note"))),
464 Ok(Some(n)) => n,
465 };
466 this.notes.push(note);
467 }
468 count = match ReadUSize(&mut buf_reader) {
469 Err(e) => return Err(ConstructorError::FileIOError(String::from("Reading Options count"),e.to_string())),
470 Ok(None) => return Err(ConstructorError::PrematureEOF(String::from("Reading Options count"))),
471 Ok(Some(s)) => s,
472 };
473 for i in 0..count {
474 let optkey = match Self::ReadNote(&mut buf_reader) {
475 Err(e) => return Err(ConstructorError::FileIOError(String::from("Reading Options key"),e.to_string())),
476 Ok(None) => return Err(ConstructorError::PrematureEOF(String::from("Reading Options key"))),
477 Ok(Some(n)) => n,
478 };
479 let optval = match Self::ReadNote(&mut buf_reader) {
480 Err(e) => return Err(ConstructorError::FileIOError(String::from("Reading Options value"),e.to_string())),
481 Ok(None) => return Err(ConstructorError::PrematureEOF(String::from("Reading Options value"))),
482 Ok(Some(n)) => n,
483 };
484 this.print_options.insert(optkey,optval);
485 }
486 Ok(this)
487 }
488 pub fn new(name: String,timescale: u32,timeinterval: u32) -> Self {
497 Self {name: name, filepath: PathBuf::new(), timescale: timescale,
498 timeinterval: timeinterval, stations: Vec::new(),
499 cabs: HashMap::new(), trains: HashMap::new(), notes: Vec::new(),
500 print_options: HashMap::new(), table_of_contents_p: true,
501 direction_name: String::new() }
502 }
503 pub fn AddStation(&mut self,name: String,smile: f64) -> Option<usize> {
515 match self.FindStationByName(name.clone()) {
516 None => match self.stations.last() {
517 None => {
518 self.stations.push(Station::new(name.clone(),smile));
519 Some(self.stations.len()-1)
520 },
521 Some(l) =>
522 if l.SMile() < smile {
523 self.stations.push(Station::new(name.clone(),smile));
524 Some(self.stations.len()-1)
525 } else {
526 None
527 },
528 },
529 Some(index) => Some(index),
530 }
531 }
532 pub fn FindStationByName(&self,name: String) -> Option<usize> {
540 for i in 0..self.stations.len() {
541 if self.stations[i].Name() == name {
542 return Some(i);
543 }
544 }
545 None
546 }
547 pub fn NumberOfStations(&self) -> usize {self.stations.len()}
552 pub fn IthStation(&self, i: usize) -> Option<&Station> {
560 self.stations.get(i)
561 }
562 pub fn IthStationMut(&mut self, i: usize) -> Option<&mut Station> {
563 self.stations.get_mut(i)
564 }
565 pub fn StationName(&self,i: usize) -> Option<String> {
573 match self.stations.get(i) {
574 None => None,
575 Some(s) => Some(s.Name())
576 }
577 }
578 pub fn SMile(&self,i: usize) -> Option<f64> {
586 match self.stations.get(i) {
587 None => None,
588 Some(s) => Some(s.SMile()),
589 }
590 }
591 pub fn TotalLength(&self) -> f64 {
597 if self.stations.len() == 0 {
598 0.0
599 } else {
600 self.stations.last().unwrap().SMile()
601 }
602 }
603 pub fn DuplicateStationIndex(&self,i: usize) -> Option<usize> {
614 match self.stations.get(i) {
615 None => None,
616 Some(s) => s.DuplicateStationIndex(),
617 }
618 }
619 pub fn SetDuplicateStationIndex(&mut self,i: usize,dup: usize) {
632 match self.stations.get_mut(i) {
633 None => (),
634 Some(s) => s.SetDuplicateStationIndex(Some(dup)),
635 };
636 }
637 pub fn AddStorageTrack(&mut self,i: usize,name: &String) -> Option<&mut StorageTrack> {
649 match self.stations.get_mut(i) {
650 None => None,
651 Some(s) => s.AddStorageTrack(name)
652 }
653 }
654 pub fn FindStorageTrack(&self,i: usize,name: &String) -> Option<&StorageTrack> {
666 match self.stations.get(i) {
667 None => None,
668 Some(s) => s.FindStorageTrack(name),
669 }
670 }
671 pub fn FindStorageTrack_mut(&mut self,i: usize,name: &String) -> Option<&mut StorageTrack> {
672 match self.stations.get_mut(i) {
673 None => None,
674 Some(s) => s.FindStorageTrack_mut(name),
675 }
676 }
677 pub fn AddCab(&mut self,name: String,color: String) -> &Cab {
688 self.cabs.entry(name.clone()).or_insert(Cab::new(name.clone(),color))
689 }
690 pub fn FindCab(&self,name: &String) -> Option<&Cab> {
698 self.cabs.get(name)
699 }
700 pub fn NumberOfCabs(&self) -> usize {self.cabs.len()}
703 pub fn AddTrain(&mut self,name: String,number: String,speed: u32,
722 classnumber: u32, departure: u32, start: usize,
723 iend: isize) -> Result<&Train,AddTrainError> {
724 let mut end: usize;
725 if iend < 0 {
726 end = self.NumberOfStations()-1;
727 if start == end {end = 0;}
728 } else {
729 end = iend as usize;
730 }
731 if start == end {
732 Err(AddTrainError::EmptyStopList)
733 } else {
734 let startsmile = self.stations[start].SMile();
735 let newTrain = Train::new(name,number.clone(),speed,classnumber,departure,startsmile,start,end);
736 Ok(self.trains.entry(number).or_insert(newTrain))
737 }
738 }
739 pub fn AddTrainLongVersion(&mut self,name: String,number: String,
759 speed: u32,classnumber: u32,departure: u32,
760 start: usize,end: usize,
761 layoverVector: &DoubleVector,
762 cabnameVector: &StringList,
763 storageTrackVector: &StringList)
764 -> Result<&Train,AddTrainError> {
765 match self.FindTrainByNumber(&number) {
766 Some(t) => return Err(AddTrainError::DuplicateTrain),
770 None => {
771 if start == end {
775 return Err(AddTrainError::EmptyStopList)
776 } else {
777 let incr: bool;
784 let nstops: usize;
785 if start < end {
786 incr = true;
787 nstops = (end-start)+1;
788 } else {
789 incr = false;
790 nstops = (start-end)+1;
791 }
792 if layoverVector.len() != nstops ||
797 cabnameVector.len() != nstops ||
798 storageTrackVector.len() != nstops {
799 return Err(AddTrainError::RangeError(
800 if layoverVector.len() != nstops {
801 String::from("layover vector")
802 } else if cabnameVector.len() != nstops {
803 String::from("cabname vector")
804 } else if storageTrackVector.len() != nstops {
805 String::from("storage track vector")
806 } else {
807 String::new()
808 }));
809 }
810 let mut istop: usize = start;
812 let mut layoverIter = layoverVector.iter();
813 let mut storageTrackIter = storageTrackVector.iter();
815 let mut oldDepart: f64 = -1.0;
816 let mut oldSmile: f64 = -1.0;
817 for i in 0..nstops {
818 let layover = *layoverIter.next().unwrap();
819 let station = match self.IthStation(istop) {
820 Some(s) => s,
821 None =>
822 return Err(AddTrainError::BadStationNumber(istop)),
823 };
824 let smile = station.SMile();
825 let arrival: f64;
826 if oldDepart >= 0.0 {
827 arrival = oldDepart +
828 ((smile - oldSmile).abs() * (speed as f64 / 60.0));
829 } else {
830 arrival = departure as f64;
831 }
832 let depart = arrival + layover;
833 oldDepart = depart;
834 oldSmile = smile;
835 let storageTrackName: &String = storageTrackIter.next().unwrap();
836 if storageTrackName.len()> 0 {
837 let storage = station.FindStorageTrack(storageTrackName);
838 let rStation = match station.DuplicateStationIndex() {
839 None => None,
840 Some(rStationIndex) =>
841 self.IthStation(rStationIndex),
842 };
843 let rStorage = match rStation {
844 None => None,
845 Some(rs) => rs.FindStorageTrack(storageTrackName),
846 };
847 if istop == start {
848 match storage {
849 None => (),
850 Some(s) => match s.IncludesTime(departure as f64) {
851 None => (),
852 Some(o) => {
853 let tn2 = o.TrainNum2();
854 if tn2.len() > 0 {
855 return Err(AddTrainError::DuplicateStorageIsAt(storageTrackName.to_string(),tn2,station.Name()));
856 }
857 }
858 }
859 };
860 match rStorage {
861 None => (),
862 Some(s) => match s.IncludesTime(departure as f64) {
863 None => (),
864 Some(o) => {
865 let tn2 = o.TrainNum2();
866 if tn2.len() > 0 {
867 return Err(AddTrainError::DuplicateStorageIsAt(storageTrackName.to_string(),tn2,rStation.unwrap().Name()));
868 }
869 },
870 },
871 };
872 } else if istop == end {
873 match storage {
874 None => (),
875 Some(s) => match s.IncludesTime(arrival) {
876 None => (),
877 Some(o) => {
878 let tn = o.TrainNum();
879 if tn.len() > 0 {
880 return Err(AddTrainError::DuplicateStorageIsAt(storageTrackName.to_string(),tn,station.Name()));
881 }
882 }
883 }
884 };
885 match rStorage {
886 None => (),
887 Some(s) => match s.IncludesTime(arrival) {
888 None => (),
889 Some(o) => {
890 let tn = o.TrainNum();
891 if tn.len() > 0 {
892 return Err(AddTrainError::DuplicateStorageIsAt(storageTrackName.to_string(),tn,rStation.unwrap().Name()));
893 }
894 }
895 }
896 };
897 } else if layover > 0.0 && storage.is_some() {
898 let o1 = storage.unwrap().IncludesTime(arrival);
899 let o2 = storage.unwrap().IncludesTime(depart);
900 if o1.is_some() || o2.is_some() {
901 return Err(AddTrainError::DuplicateStorageAt(storageTrackName.to_string(),station.Name()));
902 }
903 match rStorage {
904 None => (),
905 Some(rs) => {
906 let o1 = rs.IncludesTime(arrival);
907 let o2 = rs.IncludesTime(depart);
908 if o1.is_some() || o2.is_some() {
909 return Err(AddTrainError::DuplicateStorageAt(storageTrackName.to_string(),rStation.unwrap().Name()));
910 }
911 },
912 };
913 }
914 }
915 if incr {
916 istop += 1;
917 } else {
918 istop -= 1;
919 }
920 }
921 let startsmile = self.stations[start].SMile();
925 let mut newTrain = Train::new(name,number.clone(),speed,classnumber,departure,startsmile,start,end);
926 let mut istop: usize = start;
931 let mut layoverIter = layoverVector.iter();
932 let mut cabnameIter = cabnameVector.iter();
933 let mut storageTrackIter = storageTrackVector.iter();
934 let mut oldDepart: f64 = -1.0;
935 let mut oldSmile: f64 = -1.0;
936 for i in 0..nstops {
937 let layover = *layoverIter.next().unwrap();
938 newTrain.UpdateStopLayover(istop,layover);
939 let cabName = cabnameIter.next().unwrap();
940 if cabName.len() > 0 {
941 let cab = self.FindCab(cabName).unwrap();
942 newTrain.UpdateStopCab(istop,Some(cab));
943 } else {
944 newTrain.UpdateStopCab(istop,None);
945 }
946 let storageTrackName = storageTrackIter.next().unwrap();
947 let station = self.IthStation(istop).unwrap();
948 let smile = station.SMile();
949 let arrival: f64;
950 if oldDepart >= 0.0 {
951 arrival = oldDepart + ((smile - oldSmile).abs() * (speed as f64 / 60.0));
952 } else {
953 arrival = departure as f64;
954 }
955 let depart = arrival + layover;
956 oldDepart = depart;
957 oldSmile = smile;
958 if storageTrackName.len() > 0 {
959 Self::UpdateTrainStorageAtStop(istop,start,end,
960 &mut self.stations,
961 storageTrackName,
962 arrival,depart,
963 layover,
964 self.timescale as f64,
965 &mut newTrain);
966 }
967 if incr {
968 istop += 1;
969 } else {
970 istop -= 1;
971 }
972 }
973 Ok(self.trains.entry(number).or_insert(newTrain))
974 }
975 },
976 }
977 }
978 fn UpdateTrainStorageAtStop(istop: usize, start: usize, end: usize,
979 stations: &mut StationVector,
980 storageTrackName: &String,
981 arrival: f64, depart: f64,
982 layover: f64,infi: f64,
983 newTrain: &mut Train) {
984 let (station, rStation) = match stations[istop].DuplicateStationIndex() {
985 None => (&mut stations[istop], None),
986 Some(rsI) => stations
987 .get_disjoint_mut([istop, rsI])
988 .map(|[s, r]| (s, Some(r)))
989 .unwrap(),
990 };
991 let storage = station.FindStorageTrack_mut(storageTrackName);
992 let rStorage = match rStation {
993 None => None,
994 Some(rs) => rs.FindStorageTrack_mut(storageTrackName),
995 };
996 if istop == start {
997 match storage {
998 None => (),
999 Some(storage) => {
1000 newTrain.SetOriginStorageTrack(storageTrackName.to_string());
1001 let occupied = storage.IncludesTime(arrival);
1002 match occupied {
1003 None => {
1004 storage.StoreTrain(String::new(),0.0,arrival,newTrain.Number());
1005 },
1006 Some(occupied) => {
1007 let from = occupied.From();
1008 let to = occupied.Until();
1009 storage.UpdateStoredTrain2(from,to,newTrain.Number());
1010 storage.UpdateStoredTrainDeparture(from,to,arrival);
1011 },
1012 }
1013 },
1014 }
1015 match rStorage {
1016 None => (),
1017 Some(rStorage) => {
1018 let occupied = rStorage.IncludesTime(arrival);
1019 match occupied {
1020 None => {
1021 rStorage.StoreTrain(String::new(),0.0,arrival,
1022 newTrain.Number());
1023 },
1024 Some(occupied) => {
1025 let from = occupied.From();
1026 let to = occupied.Until();
1027 rStorage.UpdateStoredTrain2(from,to,newTrain.Number());
1028 rStorage.UpdateStoredTrainDeparture(from,to,arrival);
1029 }
1030 }
1031 }
1032 }
1033 } else if istop == end {
1034 match storage {
1035 None => (),
1036 Some(storage) => {
1037 newTrain.SetDestinationStorageTrack(storageTrackName.to_string());
1038 let occupied = storage.IncludesTime(arrival);
1039 match occupied {
1040 None => {
1041 storage.StoreTrain(newTrain.Number(),arrival,infi,String::new());
1042 },
1043 Some(occupied) => {
1044 let from = occupied.From();
1045 let to = occupied.Until();
1046 storage.UpdateStoredTrain(from,to,newTrain.Number());
1047 storage.UpdateStoredTrainArrival(from,to,arrival);
1048 },
1049 };
1050 match rStorage {
1051 None => (),
1052 Some(rStorage) => {
1053 let occupied = rStorage.IncludesTime(arrival);
1054 match occupied {
1055 None => {
1056 rStorage.StoreTrain(newTrain.Number(),arrival,infi,String::new());
1057 },
1058 Some(occupied) => {
1059 let from = occupied.From();
1060 let to = occupied.Until();
1061 rStorage.UpdateStoredTrain(from,to,newTrain.Number());
1062 rStorage.UpdateStoredTrainArrival(from,to,arrival);
1063 },
1064 }
1065 }
1066 };
1067 },
1068 };
1069 } else if layover > 0.0 && storage.is_some() {
1070 newTrain.SetTransitStorageTrack(istop,storageTrackName.to_string());
1071 let storage = storage.unwrap();
1072 storage.StoreTrain(newTrain.Number(),arrival,depart,newTrain.Number());
1073 match rStorage {
1074 None => (),
1075 Some(rStorage) => {
1076 rStorage.StoreTrain(newTrain.Number(),arrival,depart,newTrain.Number());
1077 },
1078 };
1079 }
1080 }
1081 pub fn DeleteTrain(&mut self,number: String) -> Result<(),DeleteTrainError> {
1091 match self.trains.get_mut(&number) {
1092 None => Err(DeleteTrainError::NoSuchTrain(number.clone())),
1093 Some(oldTrain) => {
1094 let departure = oldTrain.Departure();
1098 let speed = oldTrain.Speed();
1099 let mut oldDepart: f64 = -1.0;
1100 let mut oldSmile: f64 = -1.0;
1101 for istop in 0..oldTrain.NumberOfStops() {
1102 let stop = oldTrain.StopI(istop).unwrap();
1103 let istation = stop.StationIndex();
1104 let (station, mut rStation) = match self.stations[istation].DuplicateStationIndex() {
1105 None => (&mut self.stations[istation], None),
1106 Some(rsI) => self.stations
1107 .get_disjoint_mut([istation, rsI])
1108 .map(|[s, r]| (s, Some(r)))
1109 .unwrap(),
1110 };
1111 let layover = stop.Layover();
1112 let smile = station.SMile();
1113 let arrival: f64;
1114 if oldDepart < 0.0 {
1115 arrival = departure as f64;
1116 } else {
1117 arrival = oldDepart + ((smile - oldSmile) * (speed as f64 / 60.0));
1118 }
1119 let depart: f64 = arrival + layover;
1120 oldDepart = depart;
1121 oldSmile = smile;
1122 let storageTrackName = stop.StorageTrackName();
1123 if storageTrackName.len() == 0 {continue;}
1124 let storage = station.FindStorageTrack_mut(&storageTrackName);
1125 let rStorage = match rStation {
1126 None => None,
1127 Some(ref mut rs) => rs.FindStorageTrack_mut(&storageTrackName),
1128 };
1129 match stop.Flag() {
1130 StopFlagType::Origin => {
1131 match storage {
1132 None => {
1133 return Err(DeleteTrainError::InternalMissingOcc(station.Name()));
1134 },
1135 Some(storage) => {
1136 let occupied = storage.IncludesTime(departure as f64);
1137 match occupied {
1138 None => {
1139 return Err(DeleteTrainError::InternalMissingOcc(station.Name()));
1140 },
1141 Some(occupied) => {
1142 if occupied.From() == occupied.Until() &&
1143 occupied.From() == departure as f64 &&
1144 occupied.TrainNum() == number &&
1145 occupied.TrainNum2() == number {
1146 storage.RemovedStoredTrain(occupied.From(),occupied.Until());
1147 } else {
1148 let from = occupied.From();
1149 let to = occupied.Until();
1150 storage.UpdateStoredTrain2(from,to,occupied.TrainNum());
1151 storage.UpdateStoredTrainDeparture(from,to,from);
1152 }
1153 },
1154 }
1155 }
1156 };
1157 match rStorage {
1158 None => (),
1159 Some(rStorage) => {
1160 let occupied = rStorage.IncludesTime(departure as f64);
1161 match occupied {
1162 None => {
1163 return Err(DeleteTrainError::InternalMissingOcc(rStation.unwrap().Name()));
1164 },
1165 Some(occupied) => {
1166 if occupied.From() == occupied.Until() &&
1167 occupied.From() == departure as f64 &&
1168 occupied.TrainNum() == number &&
1169 occupied.TrainNum2() == number {
1170 rStorage.RemovedStoredTrain(occupied.From(),occupied.Until());
1171 } else {
1172 let from = occupied.From();
1173 let to = occupied.Until();
1174 rStorage.UpdateStoredTrain2(from,to,occupied.TrainNum());
1175 rStorage.UpdateStoredTrainDeparture(from,to,from);
1176 }
1177 },
1178 };
1179 },
1180 };
1181 },
1182 StopFlagType::Terminate => {
1183 match storage {
1184 None => {
1185 return Err(DeleteTrainError::InternalMissingOcc(station.Name()));
1186 },
1187 Some(storage) => {
1188 let occupied = storage.IncludesTime(arrival);
1189 match occupied {
1190 None => {
1191 return Err(DeleteTrainError::InternalMissingOcc(station.Name()));
1192 },
1193 Some(occupied) => {
1194 if occupied.From() == occupied.Until() &&
1195 occupied.From() == arrival &&
1196 occupied.TrainNum() == number &&
1197 occupied.TrainNum2() == number {
1198 storage.RemovedStoredTrain(occupied.From(),occupied.Until());
1199 } else {
1200 let from = occupied.From();
1201 let to = occupied.Until();
1202 storage.UpdateStoredTrain(from,to,occupied.TrainNum());
1203 storage.UpdateStoredTrainArrival(from,to,to);
1204 }
1205 },
1206 };
1207 },
1208 };
1209 match rStorage {
1210 None => (),
1211 Some(rStorage) => {
1212 let occupied = rStorage.IncludesTime(arrival);
1213 match occupied {
1214 None => {
1215 return Err(DeleteTrainError::InternalMissingOcc(rStation.unwrap().Name()));
1216 },
1217 Some(occupied) => {
1218 if occupied.From() == occupied.Until() &&
1219 occupied.From() == arrival &&
1220 occupied.TrainNum() == number &&
1221 occupied.TrainNum2() == number {
1222 rStorage.RemovedStoredTrain(occupied.From(),occupied.Until());
1223 } else {
1224 let from = occupied.From();
1225 let to = occupied.Until();
1226 rStorage.UpdateStoredTrain(from,to,occupied.TrainNum());
1227 rStorage.UpdateStoredTrainArrival(from,to,to);
1228 }
1229 },
1230 };
1231 },
1232 };
1233 },
1234 StopFlagType::Transit => {
1235 if layover > 0.0 && storage.is_some() {
1236 let storage = storage.unwrap();
1237 let o1 = storage.IncludesTime(arrival);
1238 let o2 = storage.IncludesTime(depart);
1239 if o1 != o2 || o1.is_none() || o2.is_none() {
1240 return Err(DeleteTrainError::InternalMissingOcc(station.Name()));
1241 } else {
1242 let o1 = o1.unwrap();
1243 let o2 = o2.unwrap();
1244 storage.RemovedStoredTrain(o1.From(),o1.Until());
1245 }
1246 }
1247 if layover > 0.0 && rStorage.is_some() {
1248 let rStorage = rStorage.unwrap();
1249 let o1 = rStorage.IncludesTime(arrival);
1250 let o2 = rStorage.IncludesTime(depart);
1251 if o1 != o2 || o1.is_none() || o2.is_none() {
1252 return Err(DeleteTrainError::InternalMissingOcc(rStation.unwrap().Name()));
1253 } else {
1254 let o1 = o1.unwrap();
1255 let o2 = o2.unwrap();
1256 rStorage.RemovedStoredTrain(o1.From(),o1.Until());
1257 }
1258 }
1259 },
1260 };
1261 }
1262 self.trains.remove(&number);
1266 Ok(())
1271 }
1272 }
1273 }
1274 pub fn FindTrainByName(&self,name: &String) -> Option<&Train> {
1282 for train in self.trains.values() {
1283 if *train.Name() == *name {
1284 return Some(train);
1285 }
1286 }
1287 None
1288 }
1289 pub fn FindTrainByNumber(&self, number: &String) -> Option<&Train> {
1297 self.trains.get(number)
1298 }
1299 pub fn NumberOfTrains(&self) -> usize {self.trains.len()}
1302 pub fn NumberOfNotes(&self) -> usize {self.notes.len()}
1305 pub fn Note(&self,i: usize) -> Option<String> {
1312 self.notes.get(i).cloned()
1313 }
1314 pub fn AddNote(&mut self,newnote: String) -> usize {
1319 self.notes.push(newnote);
1320 self.notes.len()
1321 }
1322 pub fn SetNote(&mut self,i: usize,note: String) -> bool {
1332 if i == 0 || i > self.notes.len() {
1333 false
1334 } else {
1335 self.notes[i-1] = note;
1336 true
1337 }
1338 }
1339 pub fn GetPrintOption(&self,key: &str) -> Option<&String>
1347 {
1348 self.print_options.get(key)
1349 }
1350 pub fn SetPrintOption(&mut self,key: &str,value: &str) {
1360 self.print_options.insert(key.to_string(),value.to_string());
1361 }
1362 pub fn WriteNewTimeTableFile(&mut self,filename: &String,
1374 setfilename: bool) -> std::io::Result<()> {
1375 let out = File::create(filename)?;
1376 let mut fp = BufWriter::new(out);
1377 writeln!(fp,"{}",self.name)?;
1378 writeln!(fp,"{} {}",self.timescale,self.timeinterval)?;
1379 writeln!(fp,"{}",self.stations.len())?;
1380 for s in self.stations.iter() {
1381 s.Write(&mut fp)?;
1382 }
1383 writeln!(fp,"{}",self.cabs.len())?;
1384 for c in self.cabs.values() {
1385 c.Write(&mut fp)?;
1386 }
1387 writeln!(fp,"{}",self.trains.len())?;
1388 for t in self.trains.values() {
1389 t.Write(&mut fp)?;
1390 }
1391 writeln!(fp,"{}",self.notes.len())?;
1392 for note in self.notes.iter() {
1393 Self::WriteNote(&mut fp,note)?;
1394 writeln!(fp,"")?;
1395 }
1396 writeln!(fp,"{}",self.print_options.len())?;
1397 for (opt,val) in self.print_options.iter() {
1398 Self::WriteNote(&mut fp,opt)?;
1399 write!(fp," ")?;
1400 Self::WriteNote(&mut fp,val)?;
1401 writeln!(fp,"")?;
1402 }
1403 if setfilename {
1404 self.filepath = PathBuf::from_str(&filename).unwrap();
1405 }
1406 Ok(())
1407 }
1408 pub fn TimeScale(&self) -> u32 {self.timescale}
1411 pub fn TimeInterval(&self) -> u32 {self.timeinterval}
1414 pub fn Name(&self) -> String {self.name.clone()}
1417 pub fn Filename(&self) -> String {self.filepath.display().to_string()}
1420 pub fn StationsIter(&self) -> std::slice::Iter<'_, Station> {
1421 self.stations.iter()
1422 }
1423 pub fn StationsIter_mut(&mut self) -> std::slice::IterMut<'_, Station> {
1424 self.stations.iter_mut()
1425 }
1426 pub fn CabsIter(&self) -> std::collections::hash_map::Iter<'_, String, Cab> {
1427 self.cabs.iter()
1428 }
1429 pub fn CabsIter_mut(&mut self) -> std::collections::hash_map::IterMut<'_, String, Cab> {
1430 self.cabs.iter_mut()
1431 }
1432 pub fn TrainsIter(&self) -> std::collections::hash_map::Iter<'_, String, Train> {
1433 self.trains.iter()
1434 }
1435 pub fn TrainsIter_mut(&mut self) -> std::collections::hash_map::IterMut<'_, String, Train> {
1436 self.trains.iter_mut()
1437 }
1438 pub fn NotesIter(&self) -> std::slice::Iter<'_, String> {
1439 self.notes.iter()
1440 }
1441 pub fn NotesIter_mut(&mut self) -> std::slice::IterMut<'_, String> {
1442 self.notes.iter_mut()
1443 }
1444 pub fn PrintOptionsIter(&self) -> std::collections::hash_map::Iter<'_, String, String> {
1445 self.print_options.iter()
1446 }
1447 pub fn PrintOptionsIter_mut(&mut self) -> std::collections::hash_map::IterMut<'_, String, String> {
1448 self.print_options.iter_mut()
1449 }
1450 const BACKSLASH: char = '\\';
1454 const OPENBRACE: char = '{';
1455 const CLOSEBRACE: char = '}';
1456 pub fn CreateLaTeXTimetable(&mut self,filename: &str)
1472 -> Result<(),CreateLaTeXError> {
1473 if self.NumberOfTrains() == 0 {
1474 Err(CreateLaTeXError::NoTrainsError)
1475 } else {
1476 let StationColWidth = Self::getdouble(self.GetPrintOption("StationColWidth"),1.5);
1478 let TimeColWidth = Self::getdouble(self.GetPrintOption("TimeColWidth"),0.5);
1479 let maxTrains = ((7.0 - StationColWidth - TimeColWidth)/TimeColWidth) as usize;
1481 let UseMultipleTables: bool; let mut GroupBy: GroupMode = GroupMode::NoGrouping;
1483 if self.NumberOfTrains() >= maxTrains {
1486 UseMultipleTables = Self::getbool(self.GetPrintOption("UseMultipleTables"),true);
1487 self.table_of_contents_p = Self::getbool(self.GetPrintOption("TOCP"),true);
1488 GroupBy = match self.GetPrintOption("GroupBy") {
1489 None => GroupMode::Class,
1490 Some(g) => match g.as_str() {
1491 ""|"Class" => GroupMode::Class,
1492 _ => GroupMode::NoGrouping,
1493 },
1494 };
1495 } else {
1496 UseMultipleTables = Self::getbool(self.GetPrintOption("UseMultipleTables"),false);
1497 self.table_of_contents_p = Self::getbool(self.GetPrintOption("TOCP"),UseMultipleTables);
1498 if UseMultipleTables {
1499 GroupBy = match self.GetPrintOption("GroupBy") {
1500 None => GroupMode::Class,
1501 Some(g) => match g.as_str() {
1502 ""|"Class" => GroupMode::Class,
1503 _ => GroupMode::NoGrouping,
1504 },
1505 };
1506 }
1507 }
1508 self.direction_name = match self.GetPrintOption("DirectionName") {
1510 None => String::from("Northbound"),
1511 Some(s) => if s == "" {
1512 String::from("Northbound")
1513 } else {
1514 s.to_string()
1515 },
1516 };
1517 let NSides = match self.GetPrintOption("NSides") {
1519 None => "single",
1520 Some(s) => if s == "" {
1521 "single"
1522 } else {
1523 s
1524 }
1525 };
1526 let TimeFormat = match self.GetPrintOption("TimeFormat") {
1528 None => "24",
1529 Some(s) => if s == "" {
1530 "24"
1531 } else {
1532 s
1533 }
1534 };
1535 let AMPMFormat = match self.GetPrintOption("AMPMFormat") {
1536 None => "a",
1537 Some(s) => if s == "" {
1538 "a"
1539 } else {
1540 s
1541 }
1542 };
1543 let Title = match self.GetPrintOption("Title") {
1545 None => "My Model Railroad Timetable",
1546 Some(s) => if s == "" {
1547 "My Model Railroad Timetable"
1548 } else {
1549 s
1550 }
1551 };
1552 let SubTitle = match self.GetPrintOption("SubTitle") {
1553 None => "Employee Timetable Number 1",
1554 Some(s) => if s == "" {
1555 "Employee Timetable Number 1"
1556 } else {
1557 s
1558 }
1559 };
1560 let Date = match self.GetPrintOption("Date") {
1561 None => "\\today",
1562 Some(s) => if s == "" {
1563 "\\today"
1564 } else {
1565 s
1566 }
1567 };
1568 let ExtraPreamble = match self.GetPrintOption("ExtraPreamble") {
1570 None => "",
1571 Some(s) => s,
1572 };
1573 let BeforeTOC = match self.GetPrintOption("BeforeTOC") {
1577 None => "%\n% Insert Pre TOC material here. Cover graphic, logo, etc.\n%",
1578 Some(s) => if s == "" {
1579 "%\n% Insert Pre TOC material here. Cover graphic, logo, etc.\n%"
1580 } else {s},
1581 };
1582 let NotesTOP = match self.GetPrintOption("NotesTOP") {
1584 None => "%\n% Insert notes prefix info here.\n%",
1585 Some(s) => if s == "" {
1586 "%\n% Insert notes prefix info here.\n%"
1587 } else {s},
1588 };
1589
1590 let mut allTrains: TrainList = Vec::new();
1593 let mut forwardTrains: TrainList = Vec::new();
1594 let mut backwardTrains: TrainList = Vec::new();
1595 for tr in self.trains.values() {
1599 allTrains.push(tr);
1600 let s1 = tr.StopI(0).unwrap();
1601 let s2 = tr.StopI(1).unwrap();
1602 if s1.StationIndex() < s2.StationIndex() {
1603 forwardTrains.push(tr);
1604 } else {
1605 backwardTrains.push(tr);
1606 }
1607 }
1608 let out = File::create(filename)?;
1609 let mut fp = BufWriter::new(out);
1610 writeln!(fp, "{}nonstopmode", Self::BACKSLASH)?;
1612 if NSides == "double" {
1613 writeln!(fp, "{}documentclass[notitlepage,twoside]{{article}}",
1614 Self::BACKSLASH)?;
1615 } else {
1616 writeln!(fp, "{}documentclass[notitlepage]{{article}}",
1617 Self::BACKSLASH)?;
1618 }
1619 writeln!(fp, "\n{}usepackage{{TimeTable}}", Self::BACKSLASH)?;
1620 writeln!(fp, "{}usepackage{{supertabular}}", Self::BACKSLASH)?;
1621 writeln!(fp, "{}usepackage{{graphicx}}", Self::BACKSLASH)?;
1622 if ExtraPreamble != "" {
1623 writeln!(fp, "{}", ExtraPreamble)?;
1624 }
1625 if !self.table_of_contents_p {
1626 writeln!(fp, "{}nofiles", Self::BACKSLASH)?;
1627 }
1628 if TimeFormat == "24" {
1629 writeln!(fp, "{}newcommand{{{}shtime}}{{{}rrtimetwentyfour}}",
1630 Self::BACKSLASH,Self::BACKSLASH,Self::BACKSLASH)?;
1631 } else {
1632 writeln!(fp, "{}newcommand{{{}shtime}}{{{}rrtimetwelve{}}}",
1633 Self::BACKSLASH,Self::BACKSLASH,Self::BACKSLASH,
1634 AMPMFormat)?;
1635 }
1636 writeln!(fp, "")?;
1637 if StationColWidth != 1.5 {
1638 writeln!(fp, "{}setlength{{{}stationwidth}}{{{}in}}",
1639 Self::BACKSLASH,Self::BACKSLASH,StationColWidth)?;
1640 writeln!(fp, "{}setlength{{{}stationwidthonear}}{{{}stationwidth}}",
1641 Self::BACKSLASH,Self::BACKSLASH,Self::BACKSLASH)?;
1642 writeln!(fp, "{}advance{}stationwidthonear by -.25in",
1643 Self::BACKSLASH,Self::BACKSLASH)?;
1644 writeln!(fp, "{}setlength{{{}stationwidthtwoar}}{{{}stationwidth}}",
1645 Self::BACKSLASH,Self::BACKSLASH,Self::BACKSLASH)?;
1646 writeln!(fp, "{}advance{}stationwidthtwoar by -.25in",
1647 Self::BACKSLASH,Self::BACKSLASH)?;
1648 }
1649 if TimeColWidth != 0.5 {
1650 writeln!(fp, "{}setlength{{{}timecolumnwidth}}{{{}in}}",
1651 Self::BACKSLASH,Self::BACKSLASH,TimeColWidth)?;
1652 }
1653 writeln!(fp, "{}title{{{}}}", Self::BACKSLASH,Title)?;
1654 writeln!(fp, "{}author{{{}}}", Self::BACKSLASH,SubTitle)?;
1655 writeln!(fp, "{}date{{{}}}", Self::BACKSLASH,Date)?;
1656 writeln!(fp, "{}begin{{document}}",Self::BACKSLASH)?;
1657
1658 writeln!(fp, "{}maketitle",Self::BACKSLASH)?;
1660
1661 writeln!(fp, "{}", BeforeTOC)?;
1663
1664 if self.table_of_contents_p {
1665 writeln!(fp, "{}tableofcontents",Self::BACKSLASH)?;
1666 }
1667
1668 if UseMultipleTables && GroupBy == GroupMode::Class {
1671 self.MakeTimeTableGroupByClass(&mut fp,&allTrains,
1673 &forwardTrains,
1674 &backwardTrains)?;
1675 } else if self.NumberOfTrains() > maxTrains {
1676 self.MakeTimeTableGroupManually(&mut fp,maxTrains,
1678 &mut allTrains,
1679 &mut forwardTrains,
1680 &mut backwardTrains)?;
1681 } else {
1682 let header = match self.GetPrintOption("AllTrainsHeader") {
1684 None => "All Trains",
1685 Some(s) => if s == "" {
1686 "All Trains"
1687 } else {s},
1688 };
1689 let sectionTOP = match self.GetPrintOption("AllTrainsSectionTOP") {
1690 None => "",
1691 Some(s) => s,
1692 };
1693 forwardTrains.sort_unstable_by(|a, b| a.DepartureCompare(b));
1694 backwardTrains.sort_unstable_by(|a, b| a.DepartureCompare(b));
1695 self.MakeTimeTableOneTable(&mut fp,&allTrains,&forwardTrains,
1696 &backwardTrains,header,
1697 sectionTOP)?;
1698 }
1699 if self.NumberOfNotes() > 0 {
1701 writeln!(fp,"{}clearpage",Self::BACKSLASH)?;
1703 writeln!(fp,"{}section*{{Notes}}",Self::BACKSLASH)?;
1705 if self.table_of_contents_p {
1706 writeln!(fp,"{}addcontentsline{{toc}}{{section}}{{Notes}}",
1707 Self::BACKSLASH)?;
1708 }
1709 writeln!(fp,"{}",NotesTOP)?;
1711 writeln!(fp,"{}begin{{description}}",Self::BACKSLASH)?;
1713 for nt in 0..self.NumberOfNotes() {
1714 let mut note = self.notes[nt].clone();
1715 if !note.ends_with(['.','?','!']) {
1718 note += ".";
1719 }
1720 writeln!(fp,"{}item[{}] {}",Self::BACKSLASH,nt+1,note)?;
1721 }
1722 writeln!(fp,"{}end{{description}}",Self::BACKSLASH)?;
1723 }
1724 writeln!(fp, "{}end{{document}}", Self::BACKSLASH)?;
1726 Ok(())
1727 }
1728 }
1729 fn MakeTimeTableGroupByClass(&self,fp: &mut BufWriter<File>,
1735 allTrains: &TrainList,
1736 forwardTrains: &TrainList,
1737 backwardTrains: &TrainList)
1738 -> Result<(),CreateLaTeXError> {
1739 let mut classlist: Vec<u32> = Vec::new(); for tr in allTrains.iter() {
1742 let classnumber = tr.ClassNumber();
1743 if !classlist.contains(&classnumber) {
1744 classlist.push(classnumber);
1745 }
1746 }
1747 classlist.sort_unstable();
1748 for classI in classlist.iter() {
1751 let mut fcl: TrainList = Vec::new();
1752 let mut bcl: TrainList = Vec::new();
1753 let mut acl: TrainList = Vec::new();
1754 for tr in forwardTrains.iter() {
1755 if tr.ClassNumber() == *classI {fcl.push(tr);}
1756 }
1757 for tr in backwardTrains.iter() {
1758 if tr.ClassNumber() == *classI {bcl.push(tr);}
1759 }
1760 for tr in allTrains.iter() {
1761 if tr.ClassNumber() == *classI {acl.push(tr);}
1762 }
1763 let temp = format!("Group,{},ClassHeader",*classI);
1765 let classHeader = match self.GetPrintOption(temp.as_str()) {
1766 None => format!("Class {} trains",*classI),
1767 Some(s) => if s == "" {
1768 format!("Class {} trains",*classI)
1769 } else {s.clone()},
1770 };
1771 let temp = format!("Group,{},SectionTOP",*classI);
1773 let sectionTOP = match self.GetPrintOption(temp.as_str()) {
1774 None => "",
1775 Some(s) => s,
1776 };
1777 fcl.sort_unstable_by(|a, b| a.DepartureCompare(b));
1779 bcl.sort_unstable_by(|a, b| a.DepartureCompare(b));
1780 self.MakeTimeTableOneTable(fp,&acl,&fcl,&bcl,
1781 classHeader.as_str(),sectionTOP)?;
1782 }
1783 Ok(())
1784 }
1785 fn MakeTimeTableGroupManually(&self,fp: &mut BufWriter<File>,
1791 maxTrains: usize,allTrains: &mut TrainList,
1792 forwardTrains: &mut TrainList,
1793 backwardTrains: &mut TrainList)
1794 -> Result<(),CreateLaTeXError> {
1795 let mut igroup: u32 = 1;
1797 loop {
1798 if allTrains.is_empty() {break;}
1799 let temp = format!("Group,{},ClassHeader",igroup);
1801 let classHeader = match self.GetPrintOption(temp.as_str()) {
1802 None => format!("Class {} trains",igroup),
1803 Some(s) => if s == "" {
1804 format!("Class {} trains",igroup)
1805 } else {s.clone()},
1806 };
1807 let temp = format!("Group,{},SectionTOP",igroup);
1809 let sectionTOP = match self.GetPrintOption(temp.as_str()) {
1810 None => "",
1811 Some(s) => s,
1812 };
1813 let temp = format!("Group,{},Trains",igroup);
1815 let trainlist = match self.GetPrintOption(temp.as_str()) {
1816 None => "",
1817 Some(s) => s,
1818 };
1819 let listOfTrains = match StringListFromString(trainlist.to_string()) {
1820 None => {return Err(CreateLaTeXError::GroupSyntaxError(igroup));},
1821 Some(sl) => sl,
1822 };
1823 if listOfTrains.len() == 0 && allTrains.len() > 0 {
1826 return Err(CreateLaTeXError::GroupEmpty(igroup));
1827 }
1828 let mut fcl: TrainList = Vec::new();
1830 let mut bcl: TrainList = Vec::new();
1831 let mut acl: TrainList = Vec::new();
1832 let mut fclI: Vec<usize> = Vec::new();
1833 let mut bclI: Vec<usize> = Vec::new();
1834 let mut aclI: Vec<usize> = Vec::new();
1835 let mut I: usize = 0;
1836 for tr in allTrains.iter() {
1837 if listOfTrains.contains(&tr.Number()) {
1838 acl.push(tr);
1839 aclI.push(I);
1840 }
1841 I += 1;
1842 }
1843 for indx in aclI.iter() {
1844 allTrains.remove(*indx);
1845 }
1846 I = 0;
1847 for tr in forwardTrains.iter() {
1848 if listOfTrains.contains(&tr.Number()) {
1849 fcl.push(tr);
1850 fclI.push(I);
1851 }
1852 I += 1;
1853 }
1854 for indx in fclI.iter() {
1855 forwardTrains.remove(*indx);
1856 }
1857 I = 0;
1858 for tr in backwardTrains.iter() {
1859 if listOfTrains.contains(&tr.Number()) {
1860 bcl.push(tr);
1861 bclI.push(I);
1862 }
1863 I += 1;
1864 }
1865 for indx in bclI.iter() {
1866 backwardTrains.remove(*indx);
1867 }
1868 fcl.sort_unstable_by(|a, b| a.DepartureCompare(b));
1870 bcl.sort_unstable_by(|a, b| a.DepartureCompare(b));
1871 self.MakeTimeTableOneTable(fp,&acl,&fcl,&bcl,&classHeader,sectionTOP)?;
1872 igroup += 1;
1873 }
1874 Ok(())
1875 }
1876 fn MakeTimeTableOneTable(&self,fp: &mut BufWriter<File>,
1883 allTrains: &TrainList,forwardTrains: &TrainList,
1884 backwardTrains: &TrainList,header: &str,
1885 sectionTOP: &str) -> Result<(),CreateLaTeXError> {
1886 if backwardTrains.is_empty() {
1887 self.MakeTimeTableOneTableStationsLeft(fp,forwardTrains,header,sectionTOP)
1888 } else {
1889 self.MakeTimeTableOneTableStationsCenter(fp,forwardTrains,backwardTrains,header,sectionTOP)
1890 }
1891 }
1892 fn MakeTimeTableOneTableStationsLeft(&self,fp: &mut BufWriter<File>,
1897 trains: &TrainList,
1898 header: &str,sectionTOP: &str)
1899 -> Result<(),CreateLaTeXError> {
1900 let mut timesAtStations: TrainTimesAtStation = HashMap::new();
1901 self.ComputeTimes(trains,&mut timesAtStations); let ntrains = trains.len(); writeln!(fp,"{}clearpage",Self::BACKSLASH)?;
1906 writeln!(fp,"{}section*{{{}}}",Self::BACKSLASH,header)?;
1908 if self.table_of_contents_p {
1910 writeln!(fp,"{}addcontentsline{{toc}}{{section}}{{{}}}",
1911 Self::BACKSLASH,header)?;
1912 for tr in trains.iter() {
1913 writeln!(fp,"{}addcontentsline{{toc}}{{subsection}}{{{}}}",
1914 Self::BACKSLASH,tr.Number())?;
1915 }
1916 }
1917 writeln!(fp,"{}",sectionTOP)?;
1919 write!(fp,"{}begin{{supertabular}}{{|r|p{{{}stationwidth}}|",
1921 Self::BACKSLASH,Self::BACKSLASH)?;
1922 for itr in 0..ntrains {write!(fp,"r|")?;}
1923 writeln!(fp,"}}")?;
1924 writeln!(fp,"{}hline",Self::BACKSLASH)?;
1925 write!(fp,"&{}parbox{{{}timecolumnwidth}}{{Train number:{}{}name:{}{}class:}}",
1927 Self::BACKSLASH,Self::BACKSLASH,Self::BACKSLASH,
1928 Self::BACKSLASH,Self::BACKSLASH,Self::BACKSLASH)?;
1929 for tr in trains.iter() {
1930 let number = tr.Number();
1931 let name = tr.Name();
1932 let classnumer = tr.ClassNumber();
1933 write!(fp,"&{}parbox{{{}timecolumnwidth}}{{{}{}{}{}{}{}{}}}",
1934 Self::BACKSLASH,Self::BACKSLASH,number,
1935 Self::BACKSLASH,Self::BACKSLASH,name,
1936 Self::BACKSLASH,Self::BACKSLASH,classnumer)?;
1937 }
1938 writeln!(fp,"{}{}",Self::BACKSLASH,Self::BACKSLASH)?;
1939 writeln!(fp,"{}hline",Self::BACKSLASH)?;
1940 write!(fp,"&Notes:")?;
1942 for tr in trains.iter() {
1943 write!(fp,"&{}parbox{{{}timecolumnwidth}}{{",Self::BACKSLASH,
1944 Self::BACKSLASH)?;
1945 let numnotes = tr.NumberOfNotes();
1946 for inote in 0..numnotes {write!(fp,"{} ",
1947 tr.Note(inote).unwrap())?;}
1948 write!(fp,"}}")?;
1949 }
1950 writeln!(fp,"{}{}",Self::BACKSLASH,Self::BACKSLASH)?;
1951 writeln!(fp,"{}hline",Self::BACKSLASH)?;
1952 writeln!(fp,"Mile&Station&{}multicolumn{{{}}}{{|c|}}{{{} (Read Down)}}{}{}",
1954 Self::BACKSLASH,ntrains,self.direction_name,Self::BACKSLASH,
1955 Self::BACKSLASH)?;
1956 writeln!(fp,"{}hline",Self::BACKSLASH)?;
1957 let numstations = self.NumberOfStations();
1959 for istation in 0..numstations {
1960 let tas = match timesAtStations.get(&istation) {
1966 None => {continue;},
1967 Some(t) => t,
1968 };
1969 let station = &self.stations[istation];
1970 let smile = station.SMile();
1971 write!(fp,"&{}parbox[t]{{{}stationwidthonear}}{{{}}}{}hfill AR",
1974 Self::BACKSLASH,Self::BACKSLASH,station.Name(),
1975 Self::BACKSLASH)?;
1976 for tr in trains.iter() {
1977 write!(fp,"&")?;
1978 let st = match tas.get(&tr.Number()) {
1979 None => {continue;},
1980 Some(t) => t,
1981 };
1982 if st.Flag() != StopFlagType::Origin {
1983 write!(fp,"{}shtime{{{}}}",Self::BACKSLASH,
1984 (st.Arrival()+0.5) as u32)?;
1985 } else {
1986 let origStop = tr.StopI(0).unwrap();
1987 let tk = origStop.StorageTrackName();
1988 if tk.len() > 0 {
1989 write!(fp,"Tr {}",tk)?;
1990 }
1991 }
1992 }
1993 writeln!(fp,"{}{}",Self::BACKSLASH,Self::BACKSLASH)?;
1994 write!(fp,"{}&",smile as u32)?;
1997 for tr in trains.iter() {
1998 write!(fp,"&")?;
1999 match tas.get(&tr.Number()) {
2000 None => {continue;},
2001 Some(t) => (),
2002 };
2003 let nstops = tr.NumberOfStops();
2004 for istop in 0..nstops {
2005 let stop = tr.StopI(istop).unwrap();
2006 if stop.StationIndex() == istation {
2007 write!(fp,"{}parbox{{{}timecolumnwidth}}{{",
2008 Self::BACKSLASH,Self::BACKSLASH)?;
2009 match stop.TheCab() {
2010 None => (),
2011 Some(cab) => {
2012 write!(fp,"{}{}{}",cab.Name(),Self::BACKSLASH,
2013 Self::BACKSLASH)?;
2014 },
2015 };
2016 for inote in 0..stop.NumberOfNotes() {
2017 write!(fp,"{} ",stop.Note(inote).unwrap())?;
2018 }
2019 write!(fp,"}}")?;
2020 break;
2021 }
2022 }
2023 }
2024 writeln!(fp,"{}{}",Self::BACKSLASH,Self::BACKSLASH)?;
2025 write!(fp,"&{}hfill LV",Self::BACKSLASH)?;
2028 for tr in trains.iter() {
2029 write!(fp,"&")?;
2030 let st = match tas.get(&tr.Number()) {
2031 None => {continue;}
2032 Some(st) => st,
2033 };
2034 if st.Flag() != StopFlagType::Terminate {
2035 write!(fp,"{}shtime{{{}}}",Self::BACKSLASH,
2036 (st.Departure()+0.5) as u32)?;
2037 } else {
2038 let destStop = tr.StopI(tr.NumberOfStops()-1).unwrap();
2039 let strack = destStop.StorageTrackName();
2040 if strack.len() > 0 {
2041 write!(fp,"Tr {}",strack)?;
2042 }
2043 }
2044 }
2045 writeln!(fp,"{}{}",Self::BACKSLASH,Self::BACKSLASH)?;
2046 writeln!(fp,"{}hline",Self::BACKSLASH)?;
2047 }
2048 writeln!(fp,"{}end{{supertabular}}",Self::BACKSLASH)?;
2049 writeln!(fp,"")?;
2050 writeln!(fp,"{}vfill",Self::BACKSLASH)?;
2051 writeln!(fp,"")?;
2052 Ok(())
2053 }
2054 fn MakeTimeTableOneTableStationsCenter(&self,fp: &mut BufWriter<File>,
2060 forwardTrains: &TrainList,
2061 backwardsTrains: &TrainList,
2062 header: &str,sectionTOP: &str)
2063 -> Result<(),CreateLaTeXError> {
2064
2065 let rev = match self.direction_name.as_str() {
2067 "Northbound" => "Southbound",
2068 "Southbound" => "Northbound",
2069 "Eastbound" => "Westbound",
2070 "Westbound" => "Eastbound",
2071 _ => "",
2072 };
2073 let mut timesAtStationsForward: TrainTimesAtStation = HashMap::new();
2075 let mut timesAtStationsBackward: TrainTimesAtStation = HashMap::new();
2076 self.ComputeTimes(forwardTrains,&mut timesAtStationsForward);
2077 self.ComputeTimes(backwardsTrains,&mut timesAtStationsBackward);
2078 let nFtrains = forwardTrains.len();
2080 let nBtrains = backwardsTrains.len();
2081
2082 writeln!(fp,"{}clearpage",Self::BACKSLASH)?;
2084 writeln!(fp,"{}section*{{{}}}",Self::BACKSLASH,header)?;
2086 if self.table_of_contents_p {
2088 writeln!(fp,"{}addcontentsline{{toc}}{{section}}{{{}}}",Self::BACKSLASH,header)?;
2089 for train in forwardTrains.iter() {
2090 writeln!(fp,"{}addcontentsline{{toc}}{{subsection}}{{{}}}",Self::BACKSLASH,train.Number())?;
2091 }
2092 for train in backwardsTrains.iter() {
2093 writeln!(fp,"{}addcontentsline{{toc}}{{subsection}}{{{}}}",Self::BACKSLASH,train.Number())?;
2094 }
2095 }
2096 writeln!(fp,"{}",sectionTOP)?;
2098 write!(fp,"\n{}begin{{supertabular}}{{|",Self::BACKSLASH)?;
2100 for itr in 0..nFtrains {write!(fp,"r|")?;}
2101 write!(fp,"|r|p{{{}stationwidth}}|",Self::BACKSLASH)?;
2102 for itr in 0..nBtrains {write!(fp,"r|")?;}
2103 writeln!(fp,"}}")?;
2104 writeln!(fp,"{}hline",Self::BACKSLASH)?;
2105 for train in forwardTrains.iter() {
2107 let number = train.Number();
2108 let name = train.Name();
2109 let classnumer = train.ClassNumber();
2110 write!(fp,"{}parbox{{{}timecolumnwidth}}{{{}{}{}{}{}{}{}}}&",
2111 Self::BACKSLASH,Self::BACKSLASH,number,
2112 Self::BACKSLASH,Self::BACKSLASH,name,
2113 Self::BACKSLASH,Self::BACKSLASH,classnumer)?;
2114 }
2115 write!(fp,"{}parbox{{{}timecolumnwidth}}{{Train number:{}{}name:{}{}class:}}&",
2116 Self::BACKSLASH,Self::BACKSLASH,
2117 Self::BACKSLASH,Self::BACKSLASH,
2118 Self::BACKSLASH,Self::BACKSLASH)?;
2119 for train in backwardsTrains.iter() {
2120 let number = train.Number();
2121 let name = train.Name();
2122 let classnumer = train.ClassNumber();
2123 write!(fp,"&{}parbox{{{}timecolumnwidth}}{{{}{}{}{}{}{}{}}}",
2124 Self::BACKSLASH,Self::BACKSLASH,number,
2125 Self::BACKSLASH,Self::BACKSLASH,name,
2126 Self::BACKSLASH,Self::BACKSLASH,classnumer)?;
2127 }
2128 writeln!(fp,"{}{}",Self::BACKSLASH,Self::BACKSLASH)?;
2129 writeln!(fp,"{}hline",Self::BACKSLASH)?;
2130 for train in forwardTrains.iter() {
2131 write!(fp,"{}parbox{{{}timecolumnwidth}}{{",
2132 Self::BACKSLASH,Self::BACKSLASH)?;
2133 let numnotes = train.NumberOfNotes();
2134 for inote in 0..numnotes {
2135 write!(fp,"{} ",train.Note(inote).unwrap())?;
2136 }
2137 write!(fp,"}}&")?;
2138 }
2139 write!(fp,"Notes:&")?;
2140 for train in backwardsTrains.iter() {
2141 write!(fp,"&{}parbox{{{}timecolumnwidth}}{{",
2142 Self::BACKSLASH,Self::BACKSLASH)?;
2143 let numnotes = train.NumberOfNotes();
2144 for inote in 0..numnotes {
2145 write!(fp,"{} ",train.Note(inote).unwrap())?;
2146 }
2147 write!(fp,"}}")?;
2148 }
2149 writeln!(fp,"{}{}",Self::BACKSLASH,Self::BACKSLASH)?;
2150 writeln!(fp,"{}hline",Self::BACKSLASH)?;
2151 writeln!(fp,"{}multicolumn{{{}}}{{|c|}}{{{} (Read Down)}}&Mile&Station&{}multicolumn{{{}}}{{|c|}}{{{} (Read up)}}{}{}",
2153 Self::BACKSLASH,nFtrains,self.direction_name,
2154 Self::BACKSLASH,nBtrains,rev,
2155 Self::BACKSLASH,Self::BACKSLASH)?;
2156 writeln!(fp,"{}hline",Self::BACKSLASH)?;
2157 writeln!(fp,"{}hline",Self::BACKSLASH)?;
2158 let numstations = self.NumberOfStations();
2159 for istation in 0..numstations {
2161 let tasF = timesAtStationsForward.get(&istation);
2166 let tasB = timesAtStationsBackward.get(&istation);
2167 if tasF.is_none() && tasB.is_none() {continue;}
2168 let station = self.IthStation(istation).unwrap();
2169 let smile = station.SMile();
2170 for train in forwardTrains.iter() {
2171 match tasF.unwrap().get(&train.Number()) {
2172 Some(st) => {
2173 if st.Flag() != StopFlagType::Origin {
2174 write!(fp,"{}shtime{{{}}}",Self::BACKSLASH,
2175 (st.Arrival()+0.5) as u32)?;
2176 } else {
2177 let origStop = train.StopI(0).unwrap();
2178 let strack = origStop.StorageTrackName();
2179 if strack.len() > 0 {write!(fp,"Tr {}",strack)?;}
2180 }
2181 },
2182 None => (),
2183 };
2184 write!(fp,"&")?;
2185 }
2186 write!(fp,"&AR{}hfill{}parbox[t]{{{}stationwidthtwoar}}{{{}}}{}hfill LV",
2188 Self::BACKSLASH,Self::BACKSLASH,Self::BACKSLASH,
2189 station.Name(),Self::BACKSLASH)?;
2190 for train in backwardsTrains.iter() {
2192 match tasB.unwrap().get(&train.Number()) {
2193 Some(st) => {
2194 if st.Flag() != StopFlagType::Terminate {
2195 write!(fp,"&{}shtime{{{}}}",Self::BACKSLASH,
2196 (st.Departure()+0.5) as u32)?;
2197 } else {
2198 write!(fp,"&")?;
2199 let destStop = train.StopI(train.NumberOfStops()-1).unwrap();
2200 let strack = destStop.StorageTrackName();
2201 if strack.len() > 0 {write!(fp,"Tr {}",strack)?;}
2202 }
2203 },
2204 None => {write!(fp,"&")?;},
2205 };
2206
2207 }
2208 writeln!(fp,"{}{}",Self::BACKSLASH,Self::BACKSLASH)?;
2209 for train in forwardTrains.iter() {
2211 match tasF.unwrap().get(&train.Number()) {
2212 Some(st) => {
2213 let nstops = train.NumberOfStops();
2214 for istop in 0..nstops {
2215 let stop = train.StopI(istop).unwrap();
2216 if stop.StationIndex() == istation {
2217 write!(fp,"{}parbox{{{}timecolumnwidth}}{{",
2218 Self::BACKSLASH,Self::BACKSLASH)?;
2219 match stop.TheCab() {
2220 None => (),
2221 Some(cab) => {
2222 write!(fp,"{}{}{}",cab.Name(),
2223 Self::BACKSLASH,
2224 Self::BACKSLASH)?;
2225 },
2226 };
2227 let nnotes = stop.NumberOfNotes();
2228 for inote in 0..nnotes {
2229 write!(fp,"{} ",
2230 stop.Note(inote).unwrap())?;
2231 }
2232 write!(fp,"}}")?;
2233 }
2234 }
2235 },
2236 None => (),
2237 };
2238 write!(fp,"&")?;
2239 }
2240 write!(fp,"{}&",(smile+0.5) as u32)?;
2241 for train in backwardsTrains.iter() {
2242 write!(fp,"&")?;
2243 match tasB.unwrap().get(&train.Number()) {
2244 Some(st) => {
2245 let nstops = train.NumberOfStops();
2246 for istop in 0..nstops {
2247 let stop = train.StopI(istop).unwrap();
2248 if stop.StationIndex() == istation {
2249 write!(fp,"{}parbox{{{}timecolumnwidth}}{{",
2250 Self::BACKSLASH,Self::BACKSLASH)?;
2251 match stop.TheCab() {
2252 None => (),
2253 Some(cab) => {
2254 write!(fp,"{}{}{}",cab.Name(),
2255 Self::BACKSLASH,
2256 Self::BACKSLASH)?;
2257 },
2258 };
2259 let nnotes = stop.NumberOfNotes();
2260 for inote in 0..nnotes {
2261 write!(fp,"{} ",
2262 stop.Note(inote).unwrap())?;
2263 }
2264 write!(fp,"}}")?;
2265 }
2266 }
2267 },
2268 None => (),
2269 };
2270 }
2271 writeln!(fp,"{}{}",Self::BACKSLASH,Self::BACKSLASH)?;
2272 for train in forwardTrains.iter() {
2274 match tasF.unwrap().get(&train.Number()) {
2275 Some(st) => {
2276 if st.Flag() != StopFlagType::Terminate {
2277 write!(fp,"{}shtime{{{}}}",Self::BACKSLASH,
2278 (st.Departure()+0.5) as u32)?;
2279 } else {
2280 let destStop = train.StopI(train.NumberOfStops()-1).unwrap();
2281 let strack = destStop.StorageTrackName();
2282 if strack.len() > 0 {write!(fp,"Tr {}",strack)?;}
2283 }
2284 },
2285 None => (),
2286 };
2287 write!(fp,"&")?;
2288 }
2289 write!(fp,"&LV{}hfill AR",Self::BACKSLASH)?;
2290 for train in backwardsTrains.iter() {
2291 write!(fp,"&")?;
2292 match tasB.unwrap().get(&train.Number()) {
2293 Some(st) => {
2294 if st.Flag() != StopFlagType::Origin {
2295 write!(fp,"{}shtime{{{}}}",Self::BACKSLASH,
2296 (st.Arrival()+0.5) as u32)?;
2297 } else {
2298 let origStop = train.StopI(0).unwrap();
2299 let strack = origStop.StorageTrackName();
2300 if strack.len() > 0 {write!(fp,"Tr {}",strack)?;}
2301 }
2302 }
2303 None => (),
2304 };
2305 }
2306 writeln!(fp,"{}{}",Self::BACKSLASH,Self::BACKSLASH)?;
2307 writeln!(fp,"{}hline",Self::BACKSLASH)?;
2308 }
2309 writeln!(fp,"{}end{{supertabular}}",Self::BACKSLASH)?;
2310 writeln!(fp,"")?;
2311 writeln!(fp,"{}vfill",Self::BACKSLASH)?;
2312 writeln!(fp,"")?;
2313 Ok(())
2314 }
2315 fn ComputeTimes(&self,trains: &TrainList,
2323 timesAtStations: &mut TrainTimesAtStation) {
2324 for train in trains.iter() {
2326 let departure = train.Departure();
2327 let speed = train.Speed();
2328 let mut oldDepart: f64 = -1.0;
2329 let mut oldSmile: f64 = -1.0;
2330 let nstops = train.NumberOfStops();
2331 for i in 0..nstops {
2333 let stop = train.StopI(i).unwrap();
2334 let istop = stop.StationIndex();
2335 let station = self.IthStation(istop).unwrap();
2336 let smile = station.SMile();
2337 let arrival: f64;
2339 if oldDepart >= 0.0 {
2340 arrival = oldDepart + ((smile - oldSmile).abs() *
2342 (speed as f64/ 60.0));
2343 } else {
2344 arrival = departure as f64;
2346 }
2347 let depart = stop.Departure(arrival);
2348 let st: StationTimes = StationTimes::new(arrival,depart,stop.Flag());
2349 let stationTimes = timesAtStations.entry(istop)
2350 .or_insert(HashMap::new());
2351 stationTimes.insert(train.Number(),st);
2352 oldDepart = depart;
2353 oldSmile = smile;
2354 }
2355 }
2356 }
2357 fn getdouble(optstr: Option<&String>,default: f64) -> f64 {
2358 match optstr {
2359 None => default,
2360 Some(string) => string.parse::<f64>().unwrap_or(default),
2361 }
2362 }
2363 fn getbool(optstr: Option<&String>,default: bool) -> bool {
2364 match optstr {
2365 None => default,
2366 Some(string) => string.parse::<bool>().unwrap_or(default),
2367 }
2368 }
2369 fn ReadNote(inp: &mut BufReader<File>) -> std::io::Result<Option<String>> {
2371 let mut buffer: [u8; 1] = [0; 1];
2372 loop {
2373 let status = inp.read(&mut buffer)?;
2374 if status == 0 {return Ok(None);}
2375 let ch = buffer[0] as char;
2376 if ch == '"' {break;}
2377 }
2378 let mut EOF: bool = false;
2379 let mut result: String = String::new();
2380 loop {
2381 let mut status = inp.read(&mut buffer)?;
2382 if status == 0 {EOF = true;break;}
2383 let mut ch = buffer[0] as char;
2384 if ch == '"' {break;}
2385 if ch == '\\' {
2386 status = inp.read(&mut buffer)?;
2387 if status == 0 {EOF = true;break;}
2388 ch = buffer[0] as char;
2389 }
2390 result += &ch.to_string();
2391 }
2392 if EOF {
2393 if result.len() > 0 {
2394 Ok(Some(result))
2395 } else {
2396 Ok(None)
2397 }
2398 } else {
2399 Ok(Some(result))
2400 }
2401 }
2402 fn WriteNote(f: &mut BufWriter<File>, string: &String) -> std::io::Result<()> {
2403 write!(f,"{}",'"')?;
2404 for ch in string.chars() {
2405 if ch == '"' || ch == '\\' {
2406 write!(f,"{}",'\\')?;
2407 }
2408 write!(f,"{}",ch)?;
2409 }
2410 write!(f,"{}",'"')
2411 }
2412
2413}
2414
2415
2416
2417
2418
2419
2420
2421
2422#[cfg(test)]
2423mod tests {
2424 use super::*;
2425
2426 #[test]
2427 fn StationTimes_new () {
2428 let temp = StationTimes::new(4.2, 5.1, StopFlagType::Origin);
2429 assert_eq!(temp,StationTimes{arrival: 4.2, departure: 5.1, flag: StopFlagType::Origin });
2430 }
2431 #[test]
2432 fn StationTimes_Arrival () {
2433 let temp = StationTimes::new(4.2, 5.1, StopFlagType::Origin);
2434 assert_eq!(temp.Arrival(),4.2);
2435 }
2436 #[test]
2437 fn StationTimes_Departure () {
2438 let temp = StationTimes::new(4.2, 5.1, StopFlagType::Origin);
2439 assert_eq!(temp.Departure(),5.1);
2440 }
2441 #[test]
2442 fn StationTimes_Flag () {
2443 let temp = StationTimes::new(4.2, 5.1, StopFlagType::Origin);
2444 assert_eq!(temp.Flag(),StopFlagType::Origin);
2445 }
2446
2447 #[test]
2448 fn pub_StringListToString () {
2449 let mut temp: StringList = LinkedList::new();
2450 temp.push_back(String::from("Hello"));
2451 temp.push_back(String::from("World"));
2452 let output = StringListToString(temp);
2453 assert_eq!(output,String::from("\"Hello\",\"World\""));
2454 }
2455 #[test]
2456 fn pub_StringListFromString () {
2457 let temp = match StringListFromString(String::from("\"Hello\",\"World\"")) {
2458 None => panic!("Conversion failed"),
2459 Some(l) => l,
2460 };
2461 assert_eq!(temp.len(),2);
2462 assert_eq!(temp.front(),Some(&String::from("Hello")));
2463 assert_eq!(temp.back(),Some(&String::from("World")));
2464 }
2465
2466 #[test]
2478 fn TimeTableSystem_new () {
2479 let temp = TimeTableSystem::new(String::from("Test table"),1440,15);
2480 assert_eq!(temp,TimeTableSystem {name: String::from("Test table"),
2481 filepath: PathBuf::new(),
2482 timescale: 1440, timeinterval: 15,
2483 stations: Vec::new(),
2484 cabs: HashMap::new(),
2485 trains: HashMap::new(),
2486 notes: Vec::new(),
2487 print_options: HashMap::new(),
2488 table_of_contents_p: true,
2489 direction_name: String::new() })
2490 }
2491 #[test]
2492 fn TimeTableSystem_AddStation () {
2493 let mut temp = TimeTableSystem::new(String::from("Test table"),1440,15);
2494 assert_eq!(temp.AddStation(String::from("CWC Station"),0.0),Some(0));
2495 }
2496 #[test]
2497 fn TimeTableSystem_FindStationByName () {
2498 let mut temp = TimeTableSystem::new(String::from("Test table"),1440,15);
2499 temp.AddStation(String::from("CWC Station"),0.0);
2500 assert_eq!(temp.FindStationByName(String::from("CWC Station")),Some(0));
2501 }
2502 #[test]
2503 fn TimeTableSystem_NumberOfStations () {
2504 let mut temp = TimeTableSystem::new(String::from("Test table"),1440,15);
2505 temp.AddStation(String::from("CWC Station"),0.0);
2506 assert_eq!(temp.NumberOfStations(),1);
2507 }
2508 #[test]
2509 fn TimeTableSystem_IthStation () {
2510 let mut temp = TimeTableSystem::new(String::from("Test table"),1440,15);
2511 temp.AddStation(String::from("CWC Station"),0.0);
2512 assert_eq!(temp.IthStation(0),Some(&Station::new(String::from("CWC Station"),0.0)));
2513 }
2514 #[test]
2515 fn TimeTableSystem_StationName () {
2516 let mut temp = TimeTableSystem::new(String::from("Test table"),1440,15);
2517 temp.AddStation(String::from("CWC Station"),0.0);
2518 assert_eq!(temp.StationName(0),Some(String::from("CWC Station")));
2519 }
2520 #[test]
2521 fn TimeTableSystem_SMile () {
2522 let mut temp = TimeTableSystem::new(String::from("Test table"),1440,15);
2523 temp.AddStation(String::from("CWC Station"),0.0);
2524 assert_eq!(temp.SMile(0),Some(0.0));
2525 }
2526 #[test]
2527 fn TimeTableSystem_TotalLength () {
2528 let mut temp = TimeTableSystem::new(String::from("Test table"),1440,15);
2529 temp.AddStation(String::from("CWC Station"),0.0);
2530 temp.AddStation(String::from("Bench Station"),5.0);
2531 assert_eq!(temp.TotalLength(),5.0);
2532 }
2533 #[test]
2534 fn TimeTableSystem_DuplicateStationIndex () {
2535 let mut temp = TimeTableSystem::new(String::from("Test table"),1440,15);
2536 temp.AddStation(String::from("CWC Station"),0.0);
2537 assert_eq!(temp.DuplicateStationIndex(0),None);
2538 }
2539 #[test]
2540 fn TimeTableSystem_SetDuplicateStationIndex () {
2541 let mut temp = TimeTableSystem::new(String::from("Test table"),1440,15);
2542 temp.AddStation(String::from("CWC Station West"),0.0);
2543 temp.AddStation(String::from("Bench Station"),5.0);
2544 temp.AddStation(String::from("CWC Station East"),10.0);
2545 temp.SetDuplicateStationIndex(0,2);
2546 temp.SetDuplicateStationIndex(2,0);
2547 assert_eq!(temp.DuplicateStationIndex(0),Some(2));
2548 assert_eq!(temp.DuplicateStationIndex(2),Some(0));
2549 }
2550 #[test]
2551 fn TimeTableSystem_AddStorageTrack () {
2552 let mut temp = TimeTableSystem::new(String::from("Test table"),1440,15);
2553 temp.AddStation(String::from("CWC Station"),0.0);
2554 assert_eq!(temp.AddStorageTrack(0,&String::from("Track 1")),
2555 Some(&mut StorageTrack::new(String::from("Track 1"))));
2556 }
2557 #[test]
2558 fn TimeTableSystem_FindStorageTrack () {
2559 let mut temp = TimeTableSystem::new(String::from("Test table"),1440,15);
2560 temp.AddStation(String::from("CWC Station"),0.0);
2561 temp.AddStorageTrack(0,&String::from("Track 1"));
2562 assert_eq!(temp.FindStorageTrack(0,&String::from("Track 1")),
2563 Some(&StorageTrack::new(String::from("Track 1"))));
2564 }
2565 #[test]
2566 fn TimeTableSystem_AddCab () {
2567 let mut temp = TimeTableSystem::new(String::from("Test table"),1440,15);
2568 assert_eq!(temp.AddCab(String::from("Blue"),String::from("blue")),
2569 &Cab::new(String::from("Blue"),String::from("blue")));
2570 }
2571 #[test]
2572 fn TimeTableSystem_FindCab () {
2573 let mut temp = TimeTableSystem::new(String::from("Test table"),1440,15);
2574 temp.AddCab(String::from("Blue"),String::from("blue"));
2575 assert_eq!(temp.FindCab(&String::from("Blue")),
2576 Some(&Cab::new(String::from("Blue"),String::from("blue"))));
2577 }
2578 #[test]
2579 fn TimeTableSystem_NumberOfCabs () {
2580 let mut temp = TimeTableSystem::new(String::from("Test table"),1440,15);
2581 temp.AddCab(String::from("Blue"),String::from("blue"));
2582 assert_eq!(temp.NumberOfCabs(),1);
2583 }
2584 #[test]
2585 fn TimeTableSystem_AddTrain () {
2586 let mut temp = TimeTableSystem::new(String::from("Test table"),1440,15);
2587 temp.AddStation(String::from("CWC Station West"),0.0);
2588 temp.AddStation(String::from("Bench Station"),5.0);
2589 temp.AddStation(String::from("CWC Station East"),10.0);
2590 assert_eq!(temp.AddTrain(String::from("Test Train"),String::from("T1"),
2591 60,1,6*60,0,2),
2592 Ok(&Train::new(String::from("Test Train"),
2593 String::from("T1"),60,1,6*60,0.0,0,2)));
2594 }
2595}