]> git.tdb.fi Git - r2c2.git/blob - source/libr2c2/departures.cpp
Add a dialog and necessary support code to display departures
[r2c2.git] / source / libr2c2 / departures.cpp
1 #include "departures.h"
2 #include "layout.h"
3 #include "timetable.h"
4 #include "train.h"
5 #include "trainrouter.h"
6 #include "zone.h"
7
8 using namespace std;
9 using namespace Msp;
10
11 namespace {
12
13 bool departure_time_order(const R2C2::Departures::Departure &d1, const R2C2::Departures::Departure &d2)
14 {
15         return d1.time<d2.time;
16 }
17
18 }
19
20
21 namespace R2C2 {
22
23 Departures::Departures(const Layout &layout, const string &group):
24         zones(layout.get_zones(group))
25 {
26         const map<unsigned, Train *> &trains = layout.get_trains();
27         for(map<unsigned, Train *>::const_iterator i=trains.begin(); i!=trains.end(); ++i)
28         {
29                 Timetable *timetable = i->second->get_ai_of_type<Timetable>();
30                 (void)timetable;
31                 TrainRouter *router = i->second->get_ai_of_type<TrainRouter>();
32                 router->signal_route_changed.connect(sigc::bind(sigc::mem_fun(this, &Departures::train_route_changed), sigc::ref(*i->second)));
33                 router->signal_departed.connect(sigc::bind(sigc::mem_fun(this, &Departures::train_departed), sigc::ref(*i->second)));
34
35                 update_departures(*i->second);
36         }
37 }
38
39 void Departures::train_route_changed(const Route *, Train &train)
40 {
41         update_departures(train);
42 }
43
44 void Departures::train_departed(Train &train)
45 {
46         update_departures(train);
47 }
48
49 void Departures::update_departures(Train &train)
50 {
51         const Clock &clock = train.get_layout().get_clock();
52         Time::TimeDelta t = clock.get_current_time();
53         float rate = clock.get_rate();
54
55         list<Departure> collected_departures;
56
57         Timetable *timetable = train.get_ai_of_type<Timetable>();
58         unsigned tt_length = timetable->get_length();
59         for(unsigned i=0; i<tt_length; ++i)
60         {
61                 const Timetable::Row &row = timetable->get_row(i);
62                 if(row.type==Timetable::DEPART)
63                         if(Zone *zone = get_attached_zone(*row.target))
64                         {
65                                 Time::TimeDelta dt = row.time;
66                                 while(dt<t)
67                                         dt += Time::day;
68                                 collected_departures.push_back(Departure(*zone, train, dt));
69                         }
70         }
71
72         collected_departures.sort(departure_time_order);
73
74         TrainRouter *router = train.get_ai_of_type<TrainRouter>();
75         Time::TimeDelta departure_delay = router->get_departure_delay();
76         if(departure_delay)
77                 if(Zone *zone = get_attached_zone(*train.get_block_allocator().last()))
78                 {
79                         Departure dep(*zone, train, t+departure_delay*rate);
80
81                         list<Departure>::iterator i = collected_departures.begin();
82                         bool duplicate = false;
83                         for(; (i!=collected_departures.end() && !duplicate); ++i)
84                         {
85                                 if(i->time>dep.time)
86                                 {
87                                         duplicate = (i->time<dep.time+Time::min);
88                                         break;
89                                 }
90                                 else
91                                         duplicate = (i->time+Time::min>dep.time);
92                         }
93
94                         if(!duplicate)
95                                 collected_departures.push_back(dep);
96                 }
97
98         merge_departures(train, collected_departures);
99 }
100
101 void Departures::merge_departures(Train &train, const std::list<Departure> &collected_departures)
102 {
103         list<Departure>::iterator i = departures.begin();
104         list<Departure>::const_iterator j = collected_departures.begin();
105         while(i!=departures.end() && j!=collected_departures.end())
106         {
107                 if(i->time>j->time)
108                 {
109                         list<Departure>::iterator k = departures.insert(i, *j);
110                         signal_departure_added.emit(*k);
111                         ++j;
112                 }
113                 else if(i->train==&train)
114                 {
115                         if(i->time==j->time)
116                         {
117                                 ++i;
118                                 ++j;
119                         }
120                         else
121                         {
122                                 signal_departure_removed.emit(*i);
123                                 departures.erase(i++);
124                         }
125                 }
126                 else
127                         ++i;
128         }
129
130         for(; j!=collected_departures.end(); ++j)
131         {
132                 departures.push_back(*j);
133                 signal_departure_added.emit(departures.back());
134         }
135
136         for(; i!=departures.end(); )
137         {
138                 if(i->train==&train)
139                 {
140                         signal_departure_removed.emit(*i);
141                         departures.erase(i++);
142                 }
143                 else
144                         ++i;
145         }
146 }
147
148 Zone *Departures::get_attached_zone(const TrackChain &chain) const
149 {
150         const TrackChain::TrackSet &tracks = chain.get_tracks();
151         for(vector<Zone *>::const_iterator i=zones.begin(); i!=zones.end(); ++i)
152         {
153                 for(TrackChain::TrackSet::const_iterator j=tracks.begin(); j!=tracks.end(); ++j)
154                         if((*i)->has_track(**j))
155                                 return *i;
156         }
157
158         return 0;
159 }
160
161
162 Departures::Departure::Departure(Zone &z, Train &t, const Time::TimeDelta &m):
163         zone(&z),
164         train(&t),
165         time(m)
166 { }
167
168 } // namespace R2C2