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