#include<Wire.h>
          
          // Setup stepper
          #define IN1 8
          #define IN2 9
          #define IN3 10
          #define IN4 11
          
          //For keypad
          
          
          // For stepper
          int steps = 0;
          boolean clockwise = true;
          
          // For I2C and lift
          const int slaveNr = 5;                        // Amount of slaves attached(always +1)
          int floorButtonUp[slaveNr];                   // Array containing button information from the slaves
          int floorButtonDown[slaveNr];                 // Array containing button information from the slaves
          int floorButtonElevator[6] = {0,0,0,0,0,0};   // Array containing button information from the master
          boolean doorOpen[slaveNr];                    // If Door on floor should open, also reset floor get lift buttons
          boolean liftAvailable[slaveNr];               // Array containing which IR-modules are currently triggered
          
          int currentFloor = 0;                         // Current location of the elevator
          
          boolean movingUp = true;                      // which direction the elevator is going
          boolean moveUp = false;                       // Should the motor move clockwise
          boolean moveDown = false;                     // Should the motor move counter-clockwise
          
          void setup() {
            Serial.begin(9600);                         // Begin serial communication
          
            Wire.begin();                               // Begin I2C communication
          
            // Setup stepper
            pinMode(IN1, OUTPUT);
            pinMode(IN2, OUTPUT);
            pinMode(IN3, OUTPUT);
            pinMode(IN4, OUTPUT);
          
            // this data is send to the slaves, so set to false first
            for (int i = 0; i < slaveNr; i++) {
              doorOpen[i] = false;
              liftAvailable[i] = false;
              floorButtonUp[i] = 0;
              floorButtonDown[i] = 0;
            }
          }
          
          void loop() {
            Serial.println("getAndSendDataToAllFloors");
            getAndSendDataToAllFloors();                  // Retrieve which buttons are pressed and send the location of the elevator to the slaves
            
            Serial.println("Reading elevator buttons");
            readButtons();                                // Read the buttons connected to the master
            
            Serial.println("checkForMoveLift");
            checkForMoveLift();                           // Check to see whether the elevator needs to move
            
            Serial.println("moveLift");
            moveLift();                                   // Move the elevator to its destination
            
            Serial.print("Current lift location is ");
            Serial.println(currentFloor);
            delay(100);
            Serial.println("End of loop");
            Serial.println();
          }
          
          /*********************** I2C CODE ***********************/
          //===============================================================
          void getAndSendDataToAllFloors() {
            // For each of the connected slaves, request the currently pressed buttons and send where the elevator is and whether the door should open
            // done
          
          int i=0;
            while(i != slaveNr){
              Wire.requestFrom(i, 3);
              while (Wire.available())
              {
                floorButtonUp[i] = Wire.read();
                floorButtonDown[i] = Wire.read();
                liftAvailable[i] = Wire.read();
              }
              if(liftAvailable[i] == true){
                currentFloor = i;
              }
              Wire.beginTransmission(i);
              Wire.write(currentFloor);
              Wire.endTransmission();
              i++;
            }
          }
          //===============================================================
          void sendLiftRelatedData(int floorIndex) {
            // Sends the current floor and whether the door should open to the slave
            // done (?)
          
          int i=0;
            while(i != slaveNr){
              Wire.requestFrom(i, 3);
              while (Wire.available())
              {
                Wire.beginTransmission(i);
                Wire.write(currentFloor);
                Wire.endTransmission();
              }
              i++;
            }
          
          
          }
          //===============================================================
          boolean getButtonPressedOfFloor(int floorIndex) {
            // Requests the button states from a slave
            // done
            
          int i=0;
            while(i != slaveNr){
              Wire.requestFrom(i, 3);
              while (Wire.available())
              {
                floorButtonUp[i] = Wire.read();
                floorButtonDown[i] = Wire.read();
                liftAvailable[i] = Wire.read();
                
              }
              i++;
            }
          }
          
          /*********************** NON I2C CODE ***********************/
          //===============================================================
          void readButtons(){
            // Read all the buttons connected to the master
          
          }
          
          
          void checkForMoveLift() {
            // Main algorithm to check to where the lift should move
            Serial.print("Check to see if current floor wants to use lift: ");
            if ((floorButtonDown[currentFloor] || floorButtonUp[currentFloor] || floorButtonElevator[currentFloor]) && liftAvailable[currentFloor]) {  // If there is a button pressed for the current floor and the lift is available
              if (movingUp && (floorButtonUp[currentFloor] || floorButtonElevator[currentFloor])) {
                // If lift is moving up and floorUp is pressed, stop at current floor
                moveUp = false;
                moveDown = false;
                doorOpen[currentFloor] = true;
                floorButtonElevator[currentFloor] = false;
                Serial.println("Current floor wants to use lift");
          
                delay(3000); // Might not be nessesary
                return;
              } else if (!movingUp && (floorButtonDown[currentFloor] || floorButtonElevator[currentFloor])) {
                // If lift is moving down and floorDown is pressed, stop at current floor
                moveUp = false;
                moveDown = false;
                doorOpen[currentFloor] = true;
                floorButtonElevator[currentFloor] = false;
                Serial.println("Current floor wants to use lift");
          
                delay(3000); // Might not be nessesary
                return;
              } else if (movingUp) {
                // if lift is moving up and buttonDown is pressed and there are no buttons pressed above me, stop at current floor
                boolean stopHere = true;
                for(int i = currentFloor + 1; i < (sizeof(floorButtonUp)/sizeof(int)); i++){
                  if (floorButtonUp[i] || floorButtonDown[i] || floorButtonElevator[i]){
                    stopHere = false;
                    break;
                  }
                }
          
                if (stopHere){
                  moveUp = false;
                  moveDown = false;
                  doorOpen[currentFloor] = true;
                  floorButtonElevator[currentFloor] = false;
                  Serial.println("Current floor wants to use lift");
                  delay(3000);
                  return;
                }
              } else if (!movingUp) {
                // if lift is moving down and buttonUp is pressed and there are no buttons pressed below me, stop at current floor
                boolean stopHere = true;
                for(int i = currentFloor - 1; i >= 0; i--){
                  if (floorButtonUp[i] || floorButtonDown[i] || floorButtonElevator[i]){
                    stopHere = false;
                    break;
                  }
                }
          
                if (stopHere){
                  moveUp = false;
                  moveDown = false;
                  doorOpen[currentFloor] = true;
                  floorButtonElevator[currentFloor] = false;
                  Serial.println("Current floor wants to use lift");
                  delay(3000);
                  return;
                }
              } else {
                Serial.println("current floor wants to go in a different direction, skipping floor");
              }
            } else {
              Serial.println("Current floor does not want to use the lift");
              doorOpen[currentFloor] = false;
            }
          
            Serial.print("Check for other floor wants to use lift: ");
            if (movingUp) {   // When the lift is moving up
              // check floors above current floor to see if anyone wants to go up
              for(int i = currentFloor; i < (sizeof(floorButtonUp)/sizeof(int)); i++) {  // sizeof(int) used bacause C is a bitch https://www.arduino.cc/en/Reference/Sizeof
                if (floorButtonUp[i] || floorButtonElevator[i]) {
                  Serial.println("A floor above me wants to go up");
                  moveUp = true;
                  moveDown = false;
                  movingUp = true;
                  return;
                }
              }
              //====================================================================
              // check floors above current floor to see if anyone wants to go down
              for(int i = currentFloor; i < 0; i++) {
                if (floorButtonDown[i] || floorButtonElevator[i]) {
                  Serial.println("A floor above me wants to go down");
                  moveUp = true;
                  moveDown = false;
                  movingUp = false;
                  return;
                }
              }
              //=============================================================================
              // check floor below current floor to see if anyone wants to go down
              for(int i = currentFloor; i >= 0; i--) {
                if (floorButtonDown[i] || floorButtonElevator[i]) {
                  Serial.println("A floor below me wants to go up");
                  moveUp = false;
                  moveDown = true;
                  movingUp = false;
                  return;
                }
              }
              // check floors below current floor to see if anyone wants to go up
              for(int i = currentFloor; i >= 0; i--) {
                if (floorButtonUp[i] || floorButtonElevator[i]) {
                  Serial.println("A floor below me wants to go down");
                  moveUp = false;
                  moveDown = true;
                  movingUp = false;
                  return;
                }
              }
              Serial.println("Nothing wants to use lift");
            } else if (!movingUp) {  // When the lift is moving down
              
              // check floors below current floor to see if anyone wants to go up
              for(int i = currentFloor; i >= 0; i--) {
                if (floorButtonUp[i] || floorButtonElevator[i]) {
                  Serial.println("A floor below me wants to go up");
                  moveUp = false;
                  moveDown = true;
                  movingUp = false;
                  return;
                }
              }
              // check floor below current floor to see if anyone wants to go down
              for (int i = currentFloor; i >= 0; i--) {
                if (floorButtonDown[i] || floorButtonElevator[i]) {
                  Serial.println("A floor below me wants to go down");
                  moveUp = false;
                  moveDown = true;
                  movingUp = false;
                  return;
                }
              }
              //===============================================================
              // check floors above current floor to see if anyone wants to go down
              for (int i = currentFloor; i < (sizeof(floorButtonUp)/sizeof(int)); i++) {
                if (floorButtonDown[i] || floorButtonElevator[i]) {
                  Serial.println("A floor above me wants to go dpwn");
                  moveUp = true;
                  moveDown = false;
                  movingUp = true;
                  return;
                }
              }
              //===============================================================
              // check floors above current floor to see if anyone wants to go up
              for (int i = currentFloor; i < (sizeof(floorButtonUp)/sizeof(int)); i++) {
                if (floorButtonUp[i] || floorButtonElevator[i]) {
                  Serial.println("A floor above me wants to go up");
                  moveUp = true;
                  moveDown = false;
                  movingUp = true;
                  return;
                }
              }
            }
            Serial.println("Nothing wants to use lift");
            moveUp = false;
            moveDown = false;
          }
          
          void moveLift() {
            // Controls the lift controller
            if (moveUp) {
              Serial.println("going up");
              liftController(true);
            } else if (moveDown) {
              Serial.println("going down");
              liftController(false);
            }
          }
          
          void liftController(boolean up) {
            // Controls how many the stepping motor should rotate
            clockwise = !up;
          
            if(floorButtonElevator[5]){ //When the emergency button is pressed, stop moving the motor untill the arduino resets
              return;
            }
            
            for (int i = 0; i < 1000; i++) { // remove or increase when needed,
              // with this for loop the motor moves more between requests.
              stepper();
              delayMicroseconds(2000);
            }
          }
          
          
          // http://www.nmbtc.com/step-motors/engineering/full-half-and-microstepping/
          // Using two-phase fullstep
          void stepper() {
            // controls the steppenmotor
            switch (steps) {
            case 0:
              digitalWrite(IN1, HIGH);
              digitalWrite(IN2, HIGH);
              digitalWrite(IN3, LOW);
              digitalWrite(IN4, LOW);
              break;
            case 1:
              digitalWrite(IN1, LOW);
              digitalWrite(IN2, HIGH);
              digitalWrite(IN3, HIGH);
              digitalWrite(IN4, LOW);
              break;
            case 2:
              digitalWrite(IN1, LOW);
              digitalWrite(IN2, LOW);
              digitalWrite(IN3, HIGH);
              digitalWrite(IN4, HIGH);
              break;
            case 3:
              digitalWrite(IN1, HIGH);
              digitalWrite(IN2, LOW);
              digitalWrite(IN3, LOW);
              digitalWrite(IN4, HIGH);
              break;
            default:
              digitalWrite(IN1, LOW);
              digitalWrite(IN2, LOW);
              digitalWrite(IN3, LOW);
              digitalWrite(IN4, LOW);
              break;
            }
          
            if (clockwise) {
              steps++;
            } else {
              steps--;
            }
          
            if (steps > 3) {
              steps = 0;
            } else if (steps < 0) {
              steps = 3;
            }
          }