Fix RequestButton clearing
[cs356-p1-elevator.git] / elevator.cpp
index 3be175d..62dfb19 100644 (file)
@@ -1,11 +1,24 @@
 #include "elevator.hpp"
+#include "main.hpp"
 
-Elevator::Elevator ()
-       : door_(CLOSED)
+Elevator::Elevator (int elevator_number)
+       : state_(STATE_IDLE)
+       , wait_(0)
        , direction_(IDLE)
-       , current_position_()
+       , position_()
        , stops_()
-       , ELEVATOR_STEP(0.1)
+       , number_(elevator_number)
+{
+       // Intentionally Left Empty
+}
+
+Elevator::Elevator (int starting_floor, int elevator_number)
+       : state_(STATE_IDLE)
+       , wait_(0)
+       , direction_(IDLE)
+       , position_(starting_floor)
+       , stops_()
+       , number_(elevator_number)
 {
        // Intentionally Left Empty
 }
@@ -13,12 +26,51 @@ Elevator::Elevator ()
 bool Elevator::currently_at_stop () const
 {
        StopList::const_iterator it;
-       Stop current(current_position_, direction_);
+       Stop current(position_, direction_);
+
+       /* Calculate the number of Stops above and below our current position */
+       int stops_above = 0;
+       int stops_below = 0;
+
+       for (it = stops_.begin(); it != stops_.end(); it++)
+       {
+               if (current < *it)
+                       ++stops_above;
+
+               if (current > *it)
+                       ++stops_below;
+       }
+
+       /* Check if we are at the top. If so, only the position needs to match */
+       if (direction_ == UP && stops_above == 0)
+       {
+               for (it = stops_.begin (); it != stops_.end (); it++)
+                       if (it->getPosition() == position_)
+                               return true;
+       }
 
+       /* Check if we are at the bottom. If so, only the position needs to match */
+       if (direction_ == DOWN && stops_below == 0)
+       {
+               for (it = stops_.begin (); it != stops_.end (); it++)
+                       if (it->getPosition() == position_)
+                               return true;
+       }
+
+       /* Check if we match exactly */
        for (it = stops_.begin (); it != stops_.end (); it++)
                if (*it == current)
                        return true;
 
+       /* Check if we are IDLE. If so, only the position needs to match */
+       if (direction_ == IDLE)
+       {
+               for (it = stops_.begin (); it != stops_.end (); it++)
+                       if (it->getPosition() == position_)
+                               return true;
+       }
+
+       /* No match */
        return false;
 }
 
@@ -45,53 +97,65 @@ void Elevator::stop_at (Stop &stop)
 
 float Elevator::distance_from (Position &pos) const
 {
-       if (current_position_ > pos)
-               return current_position_ - pos;
+       if (position_ > pos)
+               return position_ - pos;
 
-       return pos - current_position_;
+       return pos - position_;
 }
 
-void Elevator::move ()
+float Elevator::distance_from (Stop &s) const
 {
-       static int wait = 0;
+       Direction d = s.getDirection();
+       Position  p = s.getPosition ();
 
-       /* Wait around if we need to.
-        *
-        * This is an artificial delay to make the elevators work in a
-        * much more natural fashion. This allows some delay to leave the
-        * doors open, or for the user to press floor selection buttons
-        * before the elevator starts moving
-        */
-       if (wait > 0)
-       {
-               --wait;
-               return;
-       }
+       /* If direction doesn't matter, then only position does */
+       if (d == ALL || direction_ == IDLE)
+               return distance_from (p);
 
-       /* close the door if it is open. This is a requirement to move */
-       if (door_ != CLOSED)
-       {
-               wait = 10;
-               close_door ();
-               return;
-       }
+       /* If we're not in the same direction, then we're "really far" away */
+       if (d != direction_)
+               return INT_MAX;
 
-       if (currently_at_stop ())
-       {
-               wait = 10;                                                                      // delay around for 10 steps
-               stops_.remove (Stop(current_position_, direction_));
-               open_door ();                                                           // call into the GUI to open the door
-               return;
-       }
+       /* We must be in the correct direction, so pure distance is fine */
+       return distance_from (p);
+}
 
+void Elevator::transition_move_up ()
+{
+       direction_ = UP;
+       position_ += ELEVATOR_STEP;
+
+       // TODO: Call into the GUI to update the position
+       gui_update_position_label (number_, (float)position_);
+       std::cout << "Updating the GUI with our position: " << position_ << std::endl;
+}
+
+void Elevator::transition_move_down ()
+{
+       direction_ = DOWN;
+       position_ -= ELEVATOR_STEP;
+
+       // TODO: Call into the GUI to update the position
+       gui_update_position_label (number_, (float)position_);
+       std::cout << "Updating the GUI with our position: " << position_ << std::endl;
+}
+
+void Elevator::transition_move_idle ()
+{
+       direction_ = IDLE;
+       // do not change position while IDLE
+}
+
+void Elevator::transition_open_door ()
+{
        /* Calculate the number of Stops above and below our
         * current position */
        StopList::const_iterator it;
-       Stop current = Stop(current_position_, direction_);
+       Stop current = Stop(position_, direction_);
        int stops_above = 0;
        int stops_below = 0;
 
-       for (it = stops_.begin(); it != stops_.begin(); it++)
+       for (it = stops_.begin(); it != stops_.end(); it++)
        {
                if (current < *it)
                        ++stops_above;
@@ -100,59 +164,360 @@ void Elevator::move ()
                        ++stops_below;
        }
 
-       /* Check if we need to change direction */
-       if (direction_ == UP && stops_above == 0 && stops_below > 0)
-               direction_ = DOWN;
+       /* If we are going to switch direction, clear all stops here,
+        * regardless of direction.
+        *
+        * Otherwise, just clear this stop */
+       if      (direction_ == UP && stops_above == 0)
+       {
+               stops_.remove (Stop(position_, ALL));
+               gui_unpress_request_button (number_, (int)position_);
+               gui_unpress_call_button ((int)position_, UP);
+               gui_unpress_call_button ((int)position_, DOWN);
+       }
+       else if (direction_ == DOWN && stops_below == 0)
+       {
+               stops_.remove (Stop(position_, ALL));
+               gui_unpress_request_button (number_, (int)position_);
+               gui_unpress_call_button ((int)position_, UP);
+               gui_unpress_call_button ((int)position_, DOWN);
+       }
+       else if (direction_ == IDLE)
+       {
+               stops_.remove (Stop(position_, ALL));
+               gui_unpress_request_button (number_, (int)position_);
+               gui_unpress_call_button ((int)position_, UP);
+               gui_unpress_call_button ((int)position_, DOWN);
+       }
+       else
+       {
+               stops_.remove (Stop(position_, direction_));
+               gui_unpress_call_button ((int)position_, direction_);
+               gui_unpress_request_button (number_, (int)position_);
+       }
 
-       if (direction_ == DOWN && stops_below == 0 && stops_above > 0)
-               direction_ = UP;
+       // TODO: Call into the GUI to open the door
+       gui_open_door (number_, (int)position_);
+       std::cout << "Opening Door" << std::endl;
+}
 
-       if (stops_above == 0 && stops_below == 0)
-               direction_ = IDLE;
+void Elevator::transition_close_door ()
+{
+       // TODO: Call into the GUI to close the door
+       gui_close_door (number_, (int)position_);
+       std::cout << "Closing Door" << std::endl;
+}
+
+void Elevator::transition_begin_wait ()
+{
+       wait_ = 10;
+}
+
+void Elevator::transition_continue_wait ()
+{
+       --wait_;
+}
+
+#include <string>
+static void debug (const std::string& s)
+{
+       std::cout << s << std::endl;
+}
 
+static std::string get_state_name (State s)
+{
+       std::string sname;
 
-       /* Move in the correct direction */
-       switch (direction_)
+       switch (s)
        {
-               case IDLE:
+               case STATE_IDLE:
+                       sname = "STATE_IDLE";
+                       break;
+               case STATE_UP:
+                       sname = "STATE_UP";
+                       break;
+               case STATE_DOWN:
+                       sname = "STATE_DOWN";
                        break;
-               case UP:
-                       current_position_ += ELEVATOR_STEP;
+               case STATE_WAIT:
+                       sname = "STATE_WAIT";
                        break;
-               case DOWN:
-                       current_position_ -= ELEVATOR_STEP;
+               case STATE_OPEN_DOOR:
+                       sname = "STATE_OPEN_DOOR";
+                       break;
+               case STATE_CLOSE_DOOR:
+                       sname = "STATE_CLOSE_DOOR";
                        break;
                default:
-                       std::cout << __FILE__ << ":" << __LINE__ << " Unhandled Elevator Position" << std::endl;
+                       sname = "BAD STATE";
                        break;
        }
 
-       /* Call the GUI with our updated position */
-       update_position ();
+       return sname;
 }
 
-bool Elevator::is_idle () const
+static std::string get_event_name (Event e)
 {
-       return direction_ == IDLE;
+       std::string ename;
+
+       switch (e)
+       {
+               case EVT_IDLE:
+                       ename = "EVT_IDLE";
+                       break;
+               case EVT_UP:
+                       ename = "EVT_UP";
+                       break;
+               case EVT_DOWN:
+                       ename = "EVT_DOWN";
+                       break;
+               case EVT_WAIT:
+                       ename = "EVT_WAIT";
+                       break;
+               case EVT_OPEN_DOOR:
+                       ename = "EVT_OPEN_DOOR";
+                       break;
+               case EVT_CLOSE_DOOR:
+                       ename = "EVT_CLOSE_DOOR";
+                       break;
+               default:
+                       ename = "BAD EVENT";
+                       break;
+       }
+
+       return ename;
 }
 
-void Elevator::update_position () const
+static void bad_transition (State s, Event e)
 {
-       std::cout << "Updating the GUI with our position" << std::endl;
+       std::cout << "Bad State Transition: " << get_state_name (s)
+                         << " -> " << get_event_name (e) << std::endl;
 }
 
-void Elevator::open_door () const
+Event Elevator::find_next_event () const
 {
-       std::cout << "Opening Door" << std::endl;
+       /* Calculate the number of Stops above and below our
+        * current position */
+       StopList::const_iterator it;
+       Stop current = Stop(position_, direction_);
+       int stops_above = 0;
+       int stops_below = 0;
+
+       for (it = stops_.begin(); it != stops_.end(); it++)
+       {
+               if (current < *it)
+                       ++stops_above;
+
+               if (current > *it)
+                       ++stops_below;
+       }
+
+       /* Now figure out which state transition to make */
+       switch (state_)
+       {
+               case STATE_IDLE:
+
+                       if (currently_at_stop ())
+                               return EVT_OPEN_DOOR;
+
+                       if (stops_above > 0)
+                               return EVT_UP;
+
+                       if (stops_below > 0)
+                               return EVT_DOWN;
+
+                       return EVT_IDLE;
+
+                       break;
+               case STATE_UP:
+
+                       if (currently_at_stop ())
+                               return EVT_OPEN_DOOR;
+
+                       return EVT_UP;
+
+                       break;
+               case STATE_DOWN:
+
+                       if (currently_at_stop ())
+                               return EVT_OPEN_DOOR;
+
+                       return EVT_DOWN;
+
+                       break;
+               case STATE_WAIT:
+
+                       if (wait_ > 0)
+                               return EVT_WAIT;
+
+                       return EVT_CLOSE_DOOR;
+
+                       break;
+               case STATE_OPEN_DOOR:
+
+                       return EVT_WAIT;
+
+                       break;
+               case STATE_CLOSE_DOOR:
+
+                       if (currently_at_stop ())
+                               return EVT_OPEN_DOOR;
+
+                       if (direction_ == UP && stops_above > 0)
+                               return EVT_UP;
+
+                       if (direction_ == DOWN && stops_below > 0)
+                               return EVT_DOWN;
+
+                       /* We need to switch directions */
+                       if (direction_ == UP && stops_above == 0 && stops_below > 0)
+                               return EVT_DOWN;
+
+                       if (direction_ == DOWN && stops_below == 0 && stops_above > 0)
+                               return EVT_UP;
+
+                       return EVT_IDLE;
+
+                       break;
+               default:
+                       std::cout << "find_next_event(): Bad State" << std::endl;
+                       break;
+       }
 }
 
-void Elevator::close_door () const
+void Elevator::move ()
 {
-       std::cout << "Closing Door" << std::endl;
-}
+       /* Generate Events */
+       Event e = find_next_event ();
 
+       std::cout << "State Transition: " << get_state_name (state_) << " with "
+                         << get_event_name (e) << std::endl;
 
+       switch (state_)
+       {
+               case STATE_IDLE:
+                       switch (e)
+                       {
+                               case EVT_UP:
+                                       state_ = STATE_UP;
+                                       transition_move_up ();
+                                       break;
+                               case EVT_DOWN:
+                                       state_ = STATE_DOWN;
+                                       transition_move_down ();
+                                       break;
+                               case EVT_IDLE:
+                                       state_ = STATE_IDLE;
+                                       transition_move_idle ();
+                                       break;
+                               case EVT_OPEN_DOOR:
+                                       state_ = STATE_OPEN_DOOR;
+                                       transition_open_door ();
+                                       break;
+                               default:
+                                       bad_transition (state_, e);
+                                       break;
+                       } // end switch (e)
+                       break;
+
+               case STATE_UP:
+                       switch (e)
+                       {
+                               case EVT_UP:
+                                       state_ = STATE_UP;
+                                       transition_move_up ();
+                                       break;
+                               case EVT_OPEN_DOOR:
+                                       state_ = STATE_OPEN_DOOR;
+                                       transition_open_door ();
+                                       break;
+                               default:
+                                       bad_transition (state_, e);
+                                       break;
+                       } // end switch (e)
+                       break;
+
+               case STATE_DOWN:
+                       switch (e)
+                       {
+                               case EVT_DOWN:
+                                       state_ = STATE_DOWN;
+                                       transition_move_down ();
+                                       break;
+                               case EVT_OPEN_DOOR:
+                                       state_ = STATE_OPEN_DOOR;
+                                       transition_open_door ();
+                                       break;
+                               default:
+                                       bad_transition (state_, e);
+                                       break;
+                       } // end switch (e)
+                       break;
+
+               case STATE_WAIT:
+                       switch (e)
+                       {
+                               case EVT_WAIT:
+                                       state_ = STATE_WAIT;
+                                       transition_continue_wait ();
+                                       break;
+                               case EVT_CLOSE_DOOR:
+                                       state_ = STATE_CLOSE_DOOR;
+                                       transition_close_door ();
+                                       break;
+                               default:
+                                       bad_transition (state_, e);
+                                       break;
+                       } // end switch (e)
+                       break;
+
+               case STATE_OPEN_DOOR:
+                       switch (e)
+                       {
+                               case EVT_WAIT:
+                                       state_ = STATE_WAIT;
+                                       transition_begin_wait ();
+                                       break;
+                               default:
+                                       bad_transition (state_, e);
+                                       break;
+                       } // end switch (e)
+                       break;
 
+               case STATE_CLOSE_DOOR:
+                       switch (e)
+                       {
+                               case EVT_OPEN_DOOR:
+                                       state_ = STATE_OPEN_DOOR;
+                                       transition_open_door ();
+                                       break;
+                               case EVT_UP:
+                                       state_ = STATE_UP;
+                                       transition_move_up ();
+                                       break;
+                               case EVT_DOWN:
+                                       state_ = STATE_DOWN;
+                                       transition_move_down ();
+                                       break;
+                               case EVT_IDLE:
+                                       state_ = STATE_IDLE;
+                                       transition_move_idle ();
+                                       break;
+                               default:
+                                       bad_transition (state_, e);
+                                       break;
+                       } // end switch (e)
+                       break;
+
+               default:
+                       std::cout << "Bad State: " << get_state_name (state_) << std::endl;
+                       break;
+       }
+}
 
+bool Elevator::is_idle () const
+{
+       return direction_ == IDLE;
+}
 
 /* vim: set ts=4 sts=4 sw=4 noexpandtab textwidth=112: */