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