Fix RequestButton clearing
[cs356-p1-elevator.git] / elevator.cpp
index f034f63..62dfb19 100644 (file)
@@ -1,21 +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)
-       : door_(CLOSED)
+Elevator::Elevator (int starting_floor, int elevator_number)
+       : state_(STATE_IDLE)
+       , wait_(0)
        , direction_(IDLE)
-       , current_position_(starting_floor)
+       , position_(starting_floor)
        , stops_()
-       , ELEVATOR_STEP(0.1)
+       , number_(elevator_number)
 {
        // Intentionally Left Empty
 }
@@ -23,10 +26,9 @@ Elevator::Elevator (int starting_floor)
 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 */
+       /* Calculate the number of Stops above and below our current position */
        int stops_above = 0;
        int stops_below = 0;
 
@@ -43,7 +45,7 @@ bool Elevator::currently_at_stop () const
        if (direction_ == UP && stops_above == 0)
        {
                for (it = stops_.begin (); it != stops_.end (); it++)
-                       if (it->getPosition() == current_position_)
+                       if (it->getPosition() == position_)
                                return true;
        }
 
@@ -51,7 +53,7 @@ bool Elevator::currently_at_stop () const
        if (direction_ == DOWN && stops_below == 0)
        {
                for (it = stops_.begin (); it != stops_.end (); it++)
-                       if (it->getPosition() == current_position_)
+                       if (it->getPosition() == position_)
                                return true;
        }
 
@@ -60,6 +62,14 @@ bool Elevator::currently_at_stop () const
                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;
 }
@@ -87,50 +97,61 @@ 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_;
 }
 
-#include <string>
-static void debug (const std::string& s)
+float Elevator::distance_from (Stop &s) const
 {
-       std::cout << s << std::endl;
+       Direction d = s.getDirection();
+       Position  p = s.getPosition ();
+
+       /* If direction doesn't matter, then only position does */
+       if (d == ALL || direction_ == IDLE)
+               return distance_from (p);
+
+       /* If we're not in the same direction, then we're "really far" away */
+       if (d != direction_)
+               return INT_MAX;
+
+       /* We must be in the correct direction, so pure distance is fine */
+       return distance_from (p);
 }
 
-void Elevator::move ()
+void Elevator::transition_move_up ()
 {
-       static int wait = 0;
+       direction_ = UP;
+       position_ += ELEVATOR_STEP;
 
-       /* 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)
-       {
-               debug ("waiting");
-               --wait;
-               return;
-       }
+       // 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;
+}
 
-       /* close the door if it is open. This is a requirement to move */
-       if (door_ != CLOSED)
-       {
-               debug ("closing door");
-               wait = 10;
-               door_ = CLOSED;
-               close_door ();
-               return;
-       }
+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;
 
@@ -143,103 +164,360 @@ void Elevator::move ()
                        ++stops_below;
        }
 
-       /* Check if we are currently at a stop */
-       if (currently_at_stop ())
+       /* 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)
        {
-               std::cout << "At A Stop: " << Stop(current_position_, direction_) << std::endl;
-               std::cout << "above=" << stops_above << " below=" << stops_below << std::endl;
-               wait = 10;
-
-               /* Remove all stops here if we are switching direction */
-               if (stops_above == 0 && direction_ == UP)
-                       stops_.remove (Stop(current_position_, ALL));
-
-               if (stops_below == 0 && direction_ == DOWN)
-                       stops_.remove (Stop(current_position_, ALL));
-
-               stops_.remove (Stop(current_position_, direction_));
-
-               /* Open the door */
-               door_ = OPEN;
-               open_door ();
-
-               return;
+               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);
        }
-
-       /* Check if we need to change direction */
-       if (stops_above == 0 && stops_below > 0 && direction_ == UP)
+       else if (direction_ == DOWN && stops_below == 0)
        {
-               debug ("1: DOWN");
-               direction_ = DOWN;
+               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);
        }
-
-       if (stops_below == 0 && stops_above > 0 && direction_ == DOWN)
+       else if (direction_ == IDLE)
        {
-               debug ("2: UP");
-               direction_ = UP;
+               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);
        }
-
-       if (stops_above == 0 && stops_below == 0 && direction_ != IDLE)
+       else
        {
-               debug ("3: IDLE");
-               direction_ = IDLE;
+               stops_.remove (Stop(position_, direction_));
+               gui_unpress_call_button ((int)position_, direction_);
+               gui_unpress_request_button (number_, (int)position_);
        }
 
-       if (direction_ == IDLE && stops_above > 0)
-       {
-               debug ("4: UP");
-               direction_ = UP;
-       }
+       // TODO: Call into the GUI to open the door
+       gui_open_door (number_, (int)position_);
+       std::cout << "Opening Door" << std::endl;
+}
 
-       if (direction_ == IDLE && stops_below > 0)
-       {
-               debug ("5: DOWN");
-               direction_ = DOWN;
-       }
+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_;
+}
 
-       /* Move in the correct direction */
-       switch (direction_)
+#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;
+
+       switch (s)
        {
-               case IDLE:
+               case STATE_IDLE:
+                       sname = "STATE_IDLE";
+                       break;
+               case STATE_UP:
+                       sname = "STATE_UP";
                        break;
-               case UP:
-                       current_position_ += ELEVATOR_STEP;
+               case STATE_DOWN:
+                       sname = "STATE_DOWN";
                        break;
-               case DOWN:
-                       current_position_ -= ELEVATOR_STEP;
+               case STATE_WAIT:
+                       sname = "STATE_WAIT";
+                       break;
+               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: " << current_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: */