Fix RequestButton clearing
[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                 gui_unpress_request_button (number_, (int)position_);
197         }
198
199         // TODO: Call into the GUI to open the door
200         gui_open_door (number_, (int)position_);
201         std::cout << "Opening Door" << std::endl;
202 }
203
204 void Elevator::transition_close_door ()
205 {
206         // TODO: Call into the GUI to close the door
207         gui_close_door (number_, (int)position_);
208         std::cout << "Closing Door" << std::endl;
209 }
210
211 void Elevator::transition_begin_wait ()
212 {
213         wait_ = 10;
214 }
215
216 void Elevator::transition_continue_wait ()
217 {
218         --wait_;
219 }
220
221 #include <string>
222 static void debug (const std::string& s)
223 {
224         std::cout << s << std::endl;
225 }
226
227 static std::string get_state_name (State s)
228 {
229         std::string sname;
230
231         switch (s)
232         {
233                 case STATE_IDLE:
234                         sname = "STATE_IDLE";
235                         break;
236                 case STATE_UP:
237                         sname = "STATE_UP";
238                         break;
239                 case STATE_DOWN:
240                         sname = "STATE_DOWN";
241                         break;
242                 case STATE_WAIT:
243                         sname = "STATE_WAIT";
244                         break;
245                 case STATE_OPEN_DOOR:
246                         sname = "STATE_OPEN_DOOR";
247                         break;
248                 case STATE_CLOSE_DOOR:
249                         sname = "STATE_CLOSE_DOOR";
250                         break;
251                 default:
252                         sname = "BAD STATE";
253                         break;
254         }
255
256         return sname;
257 }
258
259 static std::string get_event_name (Event e)
260 {
261         std::string ename;
262
263         switch (e)
264         {
265                 case EVT_IDLE:
266                         ename = "EVT_IDLE";
267                         break;
268                 case EVT_UP:
269                         ename = "EVT_UP";
270                         break;
271                 case EVT_DOWN:
272                         ename = "EVT_DOWN";
273                         break;
274                 case EVT_WAIT:
275                         ename = "EVT_WAIT";
276                         break;
277                 case EVT_OPEN_DOOR:
278                         ename = "EVT_OPEN_DOOR";
279                         break;
280                 case EVT_CLOSE_DOOR:
281                         ename = "EVT_CLOSE_DOOR";
282                         break;
283                 default:
284                         ename = "BAD EVENT";
285                         break;
286         }
287
288         return ename;
289 }
290
291 static void bad_transition (State s, Event e)
292 {
293         std::cout << "Bad State Transition: " << get_state_name (s)
294                           << " -> " << get_event_name (e) << std::endl;
295 }
296
297 Event Elevator::find_next_event () const
298 {
299         /* Calculate the number of Stops above and below our
300          * current position */
301         StopList::const_iterator it;
302         Stop current = Stop(position_, direction_);
303         int stops_above = 0;
304         int stops_below = 0;
305
306         for (it = stops_.begin(); it != stops_.end(); it++)
307         {
308                 if (current < *it)
309                         ++stops_above;
310
311                 if (current > *it)
312                         ++stops_below;
313         }
314
315         /* Now figure out which state transition to make */
316         switch (state_)
317         {
318                 case STATE_IDLE:
319
320                         if (currently_at_stop ())
321                                 return EVT_OPEN_DOOR;
322
323                         if (stops_above > 0)
324                                 return EVT_UP;
325
326                         if (stops_below > 0)
327                                 return EVT_DOWN;
328
329                         return EVT_IDLE;
330
331                         break;
332                 case STATE_UP:
333
334                         if (currently_at_stop ())
335                                 return EVT_OPEN_DOOR;
336
337                         return EVT_UP;
338
339                         break;
340                 case STATE_DOWN:
341
342                         if (currently_at_stop ())
343                                 return EVT_OPEN_DOOR;
344
345                         return EVT_DOWN;
346
347                         break;
348                 case STATE_WAIT:
349
350                         if (wait_ > 0)
351                                 return EVT_WAIT;
352
353                         return EVT_CLOSE_DOOR;
354
355                         break;
356                 case STATE_OPEN_DOOR:
357
358                         return EVT_WAIT;
359
360                         break;
361                 case STATE_CLOSE_DOOR:
362
363                         if (currently_at_stop ())
364                                 return EVT_OPEN_DOOR;
365
366                         if (direction_ == UP && stops_above > 0)
367                                 return EVT_UP;
368
369                         if (direction_ == DOWN && stops_below > 0)
370                                 return EVT_DOWN;
371
372                         /* We need to switch directions */
373                         if (direction_ == UP && stops_above == 0 && stops_below > 0)
374                                 return EVT_DOWN;
375
376                         if (direction_ == DOWN && stops_below == 0 && stops_above > 0)
377                                 return EVT_UP;
378
379                         return EVT_IDLE;
380
381                         break;
382                 default:
383                         std::cout << "find_next_event(): Bad State" << std::endl;
384                         break;
385         }
386 }
387
388 void Elevator::move ()
389 {
390         /* Generate Events */
391         Event e = find_next_event ();
392
393         std::cout << "State Transition: " << get_state_name (state_) << " with "
394                           << get_event_name (e) << std::endl;
395
396         switch (state_)
397         {
398                 case STATE_IDLE:
399                         switch (e)
400                         {
401                                 case EVT_UP:
402                                         state_ = STATE_UP;
403                                         transition_move_up ();
404                                         break;
405                                 case EVT_DOWN:
406                                         state_ = STATE_DOWN;
407                                         transition_move_down ();
408                                         break;
409                                 case EVT_IDLE:
410                                         state_ = STATE_IDLE;
411                                         transition_move_idle ();
412                                         break;
413                                 case EVT_OPEN_DOOR:
414                                         state_ = STATE_OPEN_DOOR;
415                                         transition_open_door ();
416                                         break;
417                                 default:
418                                         bad_transition (state_, e);
419                                         break;
420                         } // end switch (e)
421                         break;
422
423                 case STATE_UP:
424                         switch (e)
425                         {
426                                 case EVT_UP:
427                                         state_ = STATE_UP;
428                                         transition_move_up ();
429                                         break;
430                                 case EVT_OPEN_DOOR:
431                                         state_ = STATE_OPEN_DOOR;
432                                         transition_open_door ();
433                                         break;
434                                 default:
435                                         bad_transition (state_, e);
436                                         break;
437                         } // end switch (e)
438                         break;
439
440                 case STATE_DOWN:
441                         switch (e)
442                         {
443                                 case EVT_DOWN:
444                                         state_ = STATE_DOWN;
445                                         transition_move_down ();
446                                         break;
447                                 case EVT_OPEN_DOOR:
448                                         state_ = STATE_OPEN_DOOR;
449                                         transition_open_door ();
450                                         break;
451                                 default:
452                                         bad_transition (state_, e);
453                                         break;
454                         } // end switch (e)
455                         break;
456
457                 case STATE_WAIT:
458                         switch (e)
459                         {
460                                 case EVT_WAIT:
461                                         state_ = STATE_WAIT;
462                                         transition_continue_wait ();
463                                         break;
464                                 case EVT_CLOSE_DOOR:
465                                         state_ = STATE_CLOSE_DOOR;
466                                         transition_close_door ();
467                                         break;
468                                 default:
469                                         bad_transition (state_, e);
470                                         break;
471                         } // end switch (e)
472                         break;
473
474                 case STATE_OPEN_DOOR:
475                         switch (e)
476                         {
477                                 case EVT_WAIT:
478                                         state_ = STATE_WAIT;
479                                         transition_begin_wait ();
480                                         break;
481                                 default:
482                                         bad_transition (state_, e);
483                                         break;
484                         } // end switch (e)
485                         break;
486
487                 case STATE_CLOSE_DOOR:
488                         switch (e)
489                         {
490                                 case EVT_OPEN_DOOR:
491                                         state_ = STATE_OPEN_DOOR;
492                                         transition_open_door ();
493                                         break;
494                                 case EVT_UP:
495                                         state_ = STATE_UP;
496                                         transition_move_up ();
497                                         break;
498                                 case EVT_DOWN:
499                                         state_ = STATE_DOWN;
500                                         transition_move_down ();
501                                         break;
502                                 case EVT_IDLE:
503                                         state_ = STATE_IDLE;
504                                         transition_move_idle ();
505                                         break;
506                                 default:
507                                         bad_transition (state_, e);
508                                         break;
509                         } // end switch (e)
510                         break;
511
512                 default:
513                         std::cout << "Bad State: " << get_state_name (state_) << std::endl;
514                         break;
515         }
516 }
517
518 bool Elevator::is_idle () const
519 {
520         return direction_ == IDLE;
521 }
522
523 /* vim: set ts=4 sts=4 sw=4 noexpandtab textwidth=112: */