b8cdb5000afcbcec43649c1d2a3aaa8af0e19499
[cs356-p1-elevator.git] / elevator.cpp
1 #include "elevator.hpp"
2 #include "main.hpp"
3
4 Elevator::Elevator (int elevator_number)
5         : state_(STATE_IDLE)
6         , wait_(0)
7         , direction_(IDLE)
8         , position_()
9         , stops_()
10         , number_(elevator_number)
11 {
12         // Intentionally Left Empty
13 }
14
15 Elevator::Elevator (int starting_floor, int elevator_number)
16         : state_(STATE_IDLE)
17         , wait_(0)
18         , direction_(IDLE)
19         , position_(starting_floor)
20         , stops_()
21         , number_(elevator_number)
22 {
23         // Intentionally Left Empty
24 }
25
26 bool Elevator::currently_at_stop () const
27 {
28         StopList::const_iterator it;
29         Stop current(position_, direction_);
30
31         /* Calculate the number of Stops above and below our current position */
32         int stops_above = 0;
33         int stops_below = 0;
34
35         for (it = stops_.begin(); it != stops_.end(); it++)
36         {
37                 if (current < *it)
38                         ++stops_above;
39
40                 if (current > *it)
41                         ++stops_below;
42         }
43
44         /* Check if we are at the top. If so, only the position needs to match */
45         if (direction_ == UP && stops_above == 0)
46         {
47                 for (it = stops_.begin (); it != stops_.end (); it++)
48                         if (it->getPosition() == position_)
49                                 return true;
50         }
51
52         /* Check if we are at the bottom. If so, only the position needs to match */
53         if (direction_ == DOWN && stops_below == 0)
54         {
55                 for (it = stops_.begin (); it != stops_.end (); it++)
56                         if (it->getPosition() == position_)
57                                 return true;
58         }
59
60         /* Check if we match exactly */
61         for (it = stops_.begin (); it != stops_.end (); it++)
62                 if (*it == current)
63                         return true;
64
65         /* Check if we are IDLE. If so, only the position needs to match */
66         if (direction_ == IDLE)
67         {
68                 for (it = stops_.begin (); it != stops_.end (); it++)
69                         if (it->getPosition() == position_)
70                                 return true;
71         }
72
73         /* No match */
74         return false;
75 }
76
77 void Elevator::stop_at (Stop &stop)
78 {
79         StopList::iterator it;
80
81         /* If this is an "ALL" Stop, it supercedes all others */
82         if (stop.getDirection() == ALL)
83         {
84                 stops_.remove (stop);
85                 stops_.push_back (stop);
86                 return;
87         }
88
89         /* Check if this stop already exists. If so, just leave */
90         for (it = stops_.begin(); it != stops_.end(); it++)
91                 if (*it == stop)
92                         return;
93
94         /* The stop did not already exist, so add it */
95         stops_.push_back (stop);
96 }
97
98 float Elevator::distance_from (Position &pos) const
99 {
100         if (position_ > pos)
101                 return position_ - pos;
102
103         return pos - position_;
104 }
105
106 float Elevator::distance_from (Stop &s) const
107 {
108         Direction d = s.getDirection();
109         Position  p = s.getPosition ();
110
111         /* If direction doesn't matter, then only position does */
112         if (d == ALL || direction_ == IDLE)
113                 return distance_from (p);
114
115         /* If we're not in the same direction, then we're "really far" away */
116         if (d != direction_)
117                 return INT_MAX;
118
119         /* We must be in the correct direction, so pure distance is fine */
120         return distance_from (p);
121 }
122
123 void Elevator::transition_move_up ()
124 {
125         direction_ = UP;
126         position_ += ELEVATOR_STEP;
127
128         // TODO: Call into the GUI to update the position
129         gui_update_position_label (number_, (float)position_);
130         std::cout << "Updating the GUI with our position: " << position_ << std::endl;
131 }
132
133 void Elevator::transition_move_down ()
134 {
135         direction_ = DOWN;
136         position_ -= ELEVATOR_STEP;
137
138         // TODO: Call into the GUI to update the position
139         gui_update_position_label (number_, (float)position_);
140         std::cout << "Updating the GUI with our position: " << position_ << std::endl;
141 }
142
143 void Elevator::transition_move_idle ()
144 {
145         direction_ = IDLE;
146         // do not change position while IDLE
147 }
148
149 void Elevator::transition_open_door ()
150 {
151         /* Calculate the number of Stops above and below our
152          * current position */
153         StopList::const_iterator it;
154         Stop current = Stop(position_, direction_);
155         int stops_above = 0;
156         int stops_below = 0;
157
158         for (it = stops_.begin(); it != stops_.end(); it++)
159         {
160                 if (current < *it)
161                         ++stops_above;
162
163                 if (current > *it)
164                         ++stops_below;
165         }
166
167         /* If we are going to switch direction, clear all stops here,
168          * regardless of direction.
169          *
170          * Otherwise, just clear this stop */
171         if      (direction_ == UP && stops_above == 0)
172         {
173                 stops_.remove (Stop(position_, ALL));
174                 gui_unpress_request_button (number_, (int)position_);
175                 gui_unpress_call_button ((int)position_, UP);
176                 gui_unpress_call_button ((int)position_, DOWN);
177         }
178         else if (direction_ == DOWN && stops_below == 0)
179         {
180                 stops_.remove (Stop(position_, ALL));
181                 gui_unpress_request_button (number_, (int)position_);
182                 gui_unpress_call_button ((int)position_, UP);
183                 gui_unpress_call_button ((int)position_, DOWN);
184         }
185         else if (direction_ == IDLE)
186         {
187                 stops_.remove (Stop(position_, ALL));
188                 gui_unpress_request_button (number_, (int)position_);
189                 gui_unpress_call_button ((int)position_, UP);
190                 gui_unpress_call_button ((int)position_, DOWN);
191         }
192         else
193         {
194                 stops_.remove (Stop(position_, direction_));
195                 gui_unpress_call_button ((int)position_, direction_);
196         }
197
198         // TODO: Call into the GUI to open the door
199         gui_open_door (number_, (int)position_);
200         std::cout << "Opening Door" << std::endl;
201 }
202
203 void Elevator::transition_close_door ()
204 {
205         // TODO: Call into the GUI to close the door
206         gui_close_door (number_, (int)position_);
207         std::cout << "Closing Door" << std::endl;
208 }
209
210 void Elevator::transition_begin_wait ()
211 {
212         wait_ = 10;
213 }
214
215 void Elevator::transition_continue_wait ()
216 {
217         --wait_;
218 }
219
220 #include <string>
221 static void debug (const std::string& s)
222 {
223         std::cout << s << std::endl;
224 }
225
226 static std::string get_state_name (State s)
227 {
228         std::string sname;
229
230         switch (s)
231         {
232                 case STATE_IDLE:
233                         sname = "STATE_IDLE";
234                         break;
235                 case STATE_UP:
236                         sname = "STATE_UP";
237                         break;
238                 case STATE_DOWN:
239                         sname = "STATE_DOWN";
240                         break;
241                 case STATE_WAIT:
242                         sname = "STATE_WAIT";
243                         break;
244                 case STATE_OPEN_DOOR:
245                         sname = "STATE_OPEN_DOOR";
246                         break;
247                 case STATE_CLOSE_DOOR:
248                         sname = "STATE_CLOSE_DOOR";
249                         break;
250                 default:
251                         sname = "BAD STATE";
252                         break;
253         }
254
255         return sname;
256 }
257
258 static std::string get_event_name (Event e)
259 {
260         std::string ename;
261
262         switch (e)
263         {
264                 case EVT_IDLE:
265                         ename = "EVT_IDLE";
266                         break;
267                 case EVT_UP:
268                         ename = "EVT_UP";
269                         break;
270                 case EVT_DOWN:
271                         ename = "EVT_DOWN";
272                         break;
273                 case EVT_WAIT:
274                         ename = "EVT_WAIT";
275                         break;
276                 case EVT_OPEN_DOOR:
277                         ename = "EVT_OPEN_DOOR";
278                         break;
279                 case EVT_CLOSE_DOOR:
280                         ename = "EVT_CLOSE_DOOR";
281                         break;
282                 default:
283                         ename = "BAD EVENT";
284                         break;
285         }
286
287         return ename;
288 }
289
290 static void bad_transition (State s, Event e)
291 {
292         std::cout << "Bad State Transition: " << get_state_name (s)
293                           << " -> " << get_event_name (e) << std::endl;
294 }
295
296 Event Elevator::find_next_event () const
297 {
298         /* Calculate the number of Stops above and below our
299          * current position */
300         StopList::const_iterator it;
301         Stop current = Stop(position_, direction_);
302         int stops_above = 0;
303         int stops_below = 0;
304
305         for (it = stops_.begin(); it != stops_.end(); it++)
306         {
307                 if (current < *it)
308                         ++stops_above;
309
310                 if (current > *it)
311                         ++stops_below;
312         }
313
314         /* Now figure out which state transition to make */
315         switch (state_)
316         {
317                 case STATE_IDLE:
318
319                         if (currently_at_stop ())
320                                 return EVT_OPEN_DOOR;
321
322                         if (stops_above > 0)
323                                 return EVT_UP;
324
325                         if (stops_below > 0)
326                                 return EVT_DOWN;
327
328                         return EVT_IDLE;
329
330                         break;
331                 case STATE_UP:
332
333                         if (currently_at_stop ())
334                                 return EVT_OPEN_DOOR;
335
336                         return EVT_UP;
337
338                         break;
339                 case STATE_DOWN:
340
341                         if (currently_at_stop ())
342                                 return EVT_OPEN_DOOR;
343
344                         return EVT_DOWN;
345
346                         break;
347                 case STATE_WAIT:
348
349                         if (wait_ > 0)
350                                 return EVT_WAIT;
351
352                         return EVT_CLOSE_DOOR;
353
354                         break;
355                 case STATE_OPEN_DOOR:
356
357                         return EVT_WAIT;
358
359                         break;
360                 case STATE_CLOSE_DOOR:
361
362                         if (currently_at_stop ())
363                                 return EVT_OPEN_DOOR;
364
365                         if (direction_ == UP && stops_above > 0)
366                                 return EVT_UP;
367
368                         if (direction_ == DOWN && stops_below > 0)
369                                 return EVT_DOWN;
370
371                         /* We need to switch directions */
372                         if (direction_ == UP && stops_above == 0 && stops_below > 0)
373                                 return EVT_DOWN;
374
375                         if (direction_ == DOWN && stops_below == 0 && stops_above > 0)
376                                 return EVT_UP;
377
378                         return EVT_IDLE;
379
380                         break;
381                 default:
382                         std::cout << "find_next_event(): Bad State" << std::endl;
383                         break;
384         }
385 }
386
387 void Elevator::move ()
388 {
389         /* Generate Events */
390         Event e = find_next_event ();
391
392         std::cout << "State Transition: " << get_state_name (state_) << " with "
393                           << get_event_name (e) << std::endl;
394
395         switch (state_)
396         {
397                 case STATE_IDLE:
398                         switch (e)
399                         {
400                                 case EVT_UP:
401                                         state_ = STATE_UP;
402                                         transition_move_up ();
403                                         break;
404                                 case EVT_DOWN:
405                                         state_ = STATE_DOWN;
406                                         transition_move_down ();
407                                         break;
408                                 case EVT_IDLE:
409                                         state_ = STATE_IDLE;
410                                         transition_move_idle ();
411                                         break;
412                                 case EVT_OPEN_DOOR:
413                                         state_ = STATE_OPEN_DOOR;
414                                         transition_open_door ();
415                                         break;
416                                 default:
417                                         bad_transition (state_, e);
418                                         break;
419                         } // end switch (e)
420                         break;
421
422                 case STATE_UP:
423                         switch (e)
424                         {
425                                 case EVT_UP:
426                                         state_ = STATE_UP;
427                                         transition_move_up ();
428                                         break;
429                                 case EVT_OPEN_DOOR:
430                                         state_ = STATE_OPEN_DOOR;
431                                         transition_open_door ();
432                                         break;
433                                 default:
434                                         bad_transition (state_, e);
435                                         break;
436                         } // end switch (e)
437                         break;
438
439                 case STATE_DOWN:
440                         switch (e)
441                         {
442                                 case EVT_DOWN:
443                                         state_ = STATE_DOWN;
444                                         transition_move_down ();
445                                         break;
446                                 case EVT_OPEN_DOOR:
447                                         state_ = STATE_OPEN_DOOR;
448                                         transition_open_door ();
449                                         break;
450                                 default:
451                                         bad_transition (state_, e);
452                                         break;
453                         } // end switch (e)
454                         break;
455
456                 case STATE_WAIT:
457                         switch (e)
458                         {
459                                 case EVT_WAIT:
460                                         state_ = STATE_WAIT;
461                                         transition_continue_wait ();
462                                         break;
463                                 case EVT_CLOSE_DOOR:
464                                         state_ = STATE_CLOSE_DOOR;
465                                         transition_close_door ();
466                                         break;
467                                 default:
468                                         bad_transition (state_, e);
469                                         break;
470                         } // end switch (e)
471                         break;
472
473                 case STATE_OPEN_DOOR:
474                         switch (e)
475                         {
476                                 case EVT_WAIT:
477                                         state_ = STATE_WAIT;
478                                         transition_begin_wait ();
479                                         break;
480                                 default:
481                                         bad_transition (state_, e);
482                                         break;
483                         } // end switch (e)
484                         break;
485
486                 case STATE_CLOSE_DOOR:
487                         switch (e)
488                         {
489                                 case EVT_OPEN_DOOR:
490                                         state_ = STATE_OPEN_DOOR;
491                                         transition_open_door ();
492                                         break;
493                                 case EVT_UP:
494                                         state_ = STATE_UP;
495                                         transition_move_up ();
496                                         break;
497                                 case EVT_DOWN:
498                                         state_ = STATE_DOWN;
499                                         transition_move_down ();
500                                         break;
501                                 case EVT_IDLE:
502                                         state_ = STATE_IDLE;
503                                         transition_move_idle ();
504                                         break;
505                                 default:
506                                         bad_transition (state_, e);
507                                         break;
508                         } // end switch (e)
509                         break;
510
511                 default:
512                         std::cout << "Bad State: " << get_state_name (state_) << std::endl;
513                         break;
514         }
515 }
516
517 bool Elevator::is_idle () const
518 {
519         return direction_ == IDLE;
520 }
521
522 /* vim: set ts=4 sts=4 sw=4 noexpandtab textwidth=112: */