#include <Adafruit_NeoPixel.h>
#include <LiquidCrystal_I2C.h>

const int led = 4;
const int row = 2;
const int column = 4;
const int NUMPIXELS = 4 * 8;
const int LED_Bright = 1000;

int LCD_Column = 16;
int LCD_ROW = 2;

LiquidCrystal_I2C lcd(0x27, LCD_Column, LCD_ROW);

const byte PUSH_BTN [] = {13, 12, 19, 18, 33, 32, 14, 27 };
int LED_SW [] = {0, 0, 0, 0, 0, 0, 0, 0 };
int LED_GE [] = {0, 0, 0, 0, 0, 0, 0, 0 };

int checkBox [] = {0, 0, 0, 0, 0, 0, 0, 0 };
int BOX_COUNT [] = {0, 0, 0, 0, 0, 0, 0, 0 };
int BOX_Complete [] = {0, 0, 0, 0, 0, 0, 0, 0 };

const int LED_PIN [8][4] = {
  {0, 1, 2, 3},
  {4, 5, 6, 7},
  {8, 9, 10, 11},
  {12, 13, 14, 15},
  {16, 17, 18, 19},
  {20, 21, 22, 23},
  {24, 25, 26, 27},
  {28, 29, 30, 31}
};

const int ledPin = 2;

Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, ledPin, NEO_GRB + NEO_KHZ800);

String chkList [12][7] = {
  {"0010-01246", "1", "F1BR-03-H1-05-01", "F1BR", "3087383", "6", "0"},
  {"0010-01246", "1", "F1BR-03-H1-05-01", "F1BR", "3087382", "7", "0"},
  {"0010-01246", "1", "F1BR-03-H1-05-01", "F1BR", "3087384", "8", "0"},
  {"0010-01246", "1", "F1BR-03-H1-05-01", "F1BR", "3087385", "1", "0"},
  {"0010-01578", "1", "F1BM-04-E1-03-05", "F1BM", "3087384", "8", "0"},
  {"0010-01578", "1", "F1BM-04-E1-03-05", "F1BM", "3087385", "1", "0"},
  {"0010-01671", "1", "F1BR-03-I1-01-02", "F1BR", "3087391", "5", "0"},
  {"0010-01803", "2", "F1BL-02-F1-03-02", "F1BL", "3087387", "3", "0"},
  {"0010-01810", "1", "F1BL-03-D1-03-04", "F1BL", "3087384", "8", "0"},
  {"0010-01810", "1", "F1BL-03-D1-03-04", "F1BL", "3087385", "1", "0"}
};

String intTemp = "";


void softStart() {
  Wire.begin();
  lcd.init();
  lcd.backlight();
  lcd.setCursor(0, 0);
  lcd.print("Welcome P2L");
  //Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, ledPin, NEO_GRB + NEO_KHZ800);
  pixels.setBrightness(LED_Bright);
  pixels.clear();
  for ( int i = 0 ; i < NUMPIXELS ; i++) {

    
    pixels.setPixelColor(i, pixels.Color(192, 57, 43));
    pixels.show();
    delay(200);

  }



  allLedClear();
  delay(200);
  allLedOpen(41, 128, 185);
  delay(200);
  allLedClear();
  delay(200);
  allLedOpen(41, 128, 185);
  delay(200);
  allLedClear();
  delay(200);
  allLedOpen(41, 128, 185);
  delay(200);
  allLedClear();

  for ( int i = 0 ; i < sizeof(PUSH_BTN) ; i++) {
    pinMode(PUSH_BTN[i], INPUT_PULLUP);
    delay(200);

    //Serial.println("PIN Stu: " + String(digitalRead(PUSH_BTN[i])));
  }
  lcd.init();
  lcd.setCursor(0, 0);
  lcd.print("READY!!");
  
  delay(2000);

  PLAY_NEXT_TYPE();


}
void allLedClear() {
  //Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, ledPin, NEO_GRB + NEO_KHZ800);
  //pixels.setBrightness(LED_Bright);
  pixels.clear();
  for ( int i = 0 ; i < NUMPIXELS ; i++) {
    pixels.setPixelColor(i, pixels.Color(0, 0, 0));
  }
  pixels.show();
}
void allLedOpen(int r, int g, int b) {
  //Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, ledPin, NEO_GRB + NEO_KHZ800);
  //pixels.setBrightness(LED_Bright);
  pixels.clear();
  for ( int i = 0 ; i < NUMPIXELS ; i++) {
    pixels.setPixelColor(i, pixels.Color(r, g, b));
  }
  pixels.show();
}

void openLedAlert(int rck) {

  //int startNum = rck - 1;
  //int endNum = rck;

  //Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, ledPin, NEO_GRB + NEO_KHZ800);
  //pixels.setBrightness(LED_Bright);
  pixels.clear();


  for ( int i = 0 ; i < NUMPIXELS ; i++) {

    if ((i > ((rck * 4) - 4 ) - 1) &&  (i < (rck * 4))) {
      pixels.setPixelColor(i, pixels.Color(192, 57, 43));
    }

    pixels.show();
    //delay(80);
  }


}

void closeLedAlert(int rck) {

  //int startNum = rck - 1;
  //int endNum = rck;

  //Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, ledPin, NEO_GRB + NEO_KHZ800);
  //pixels.setBrightness(LED_Bright);
  pixels.clear();
  for ( int i = (rck * 4) - 4 ; i <= rck * 4 ; i++) {
    pixels.setPixelColor(i, pixels.Color(0, 0, 0));
    pixels.show();
    //delay(80);
  }


}

void openLedalert4ea() {
  //Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, ledPin, NEO_GRB + NEO_KHZ800);
  //pixels.setBrightness(LED_Bright);
  pixels.clear();
  /* for ( int i = 0 ; i < (row * column) ; i ++) {
    for (int j = 0; j < sizeof(LED_PIN[i]) / sizeof(LED_PIN[i][0]) ; j++) {
      pixels.setPixelColor(LED_PIN[i][j], pixels.Color(0, 0, 0));
      pixels.show();
      
    }
  } */
  

  for ( int i = 0 ; i < (row * column) ; i ++) {

    if (LED_GE[i] == 1) {
      Serial.println("Get Completed : " + String(LED_SW[i]));
      for ( int j = 0; j < sizeof(LED_PIN[i]) / sizeof(LED_PIN[i][0]); j++) {
        //green RGB : rgb(39, 174, 96)
        pixels.setPixelColor(LED_PIN[i][j], pixels.Color(39, 174, 96));
        pixels.show();
      }
    } else {
      if (LED_SW[i] == 1) {
        Serial.println("Get Locking : " + String(LED_SW[i]));
        for ( int j = 0; j < sizeof(LED_PIN[i]) / sizeof(LED_PIN[i][0]); j++) {
          pixels.setPixelColor(LED_PIN[i][j], pixels.Color(192, 57, 43));
          pixels.show();
        }

        //LED_SW[i] = 1;
      } else {
        for ( int j = 0; j < sizeof(LED_PIN[i]) / sizeof(LED_PIN[i][0]); j++) {

          //Serial.println("Get LED_PIN Size :" + String(sizeof(LED_PIN[i]) / sizeof(LED_PIN[i][0]));
          pixels.setPixelColor(LED_PIN[i][j], pixels.Color(0, 0, 0));
          pixels.show();
        }
      }
    }


    Serial.print("LED " + String(i) + ":" + String(LED_SW[i]) + " ");
  }
  Serial.println("\n");
  

}
void checkLedStatus() {
  int ct = 0;
  for (int i = 0 ; i < sizeof(LED_SW) / sizeof(LED_SW[0]); i++ ) {
    if (LED_SW[i] == 1) {
      ct += 1;
    }
  }
  Serial.println("Total Bring LED num: " + String(ct));
}
void setLedStatus(int rck) {

  if (LED_SW[rck - 1] == 0) {
    LED_SW[rck - 1] = 1;
  } else {
    Serial.println("Cant change status");
  }

  openLedalert4ea();


}

void resetLedStatus(int rck) {

  if (LED_SW[rck - 1] == 1) {
    LED_SW[rck - 1] = 0;


  } else {
    Serial.println("Cant change status");
  }

  openLedalert4ea();


}

void led_Test() {
  Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, ledPin, NEO_GRB + NEO_KHZ800);
  pixels.setBrightness(LED_Bright);
  pixels.clear();

  Serial.println(sizeof(LED_PIN) / sizeof(LED_PIN[0])); // get row
  Serial.println(sizeof(LED_PIN[0]) / sizeof(LED_PIN[0][0])); // get column

  for ( int i = 0 ; i < (row * column) ; i ++) {

    if (LED_SW[i] == 1) {
      Serial.println("Get Locking : " + String(LED_SW[i]));
      for ( int j = 0; j < sizeof(LED_PIN[i]) / sizeof(LED_PIN[i][0]); j++) {

        Serial.println("Get LED_PIN Size :" + String(sizeof(LED_PIN[i])));
        pixels.setPixelColor(LED_PIN[i][j], pixels.Color(192, 57, 43));
      }

      //LED_SW[i] = 1;
    } else {
      for ( int j = 0; j < sizeof(LED_PIN[i]) / sizeof(LED_PIN[i][0]); j++) {

        Serial.println("Get LED_PIN Size :" + String(sizeof(LED_PIN[i])));
        pixels.setPixelColor(LED_PIN[i][j], pixels.Color(0, 0, 0));
      }
    }

    Serial.println("LED " + String(i) + ":" + String(LED_SW[i]));
  }


  pixels.show();
}

void Get_BOX_Count() {

  //Serial.println("Parts User Entry: " + inputValue);
  Serial.println(sizeof(chkList) / sizeof(chkList[0])); // get row
  Serial.println(sizeof(chkList[0]) / sizeof(chkList[0][0])); // get column

  for (int i = 0 ; i < sizeof(chkList) / sizeof(chkList[0]) ; i++ ) {
    int te = chkList[i][5].toInt();
    switch (te) {
      case 1:
        BOX_COUNT[0] += 1;
        break;
      case 2:
        BOX_COUNT[1] += 1;
        break;
      case 3:
        BOX_COUNT[2] += 1;
        break;
      case 4:
        BOX_COUNT[3] += 1;
        break;
      case 5:
        BOX_COUNT[4] += 1;
        break;
      case 6:
        BOX_COUNT[5] += 1;
        break;
      case 7:
        BOX_COUNT[6] += 1;
        break;
      case 8:
        BOX_COUNT[7] += 1;
        break;
    }

  }
  for (int i = 0 ; i < sizeof(BOX_COUNT) / sizeof(BOX_COUNT[0])  ; i++ ) {
    Serial.print("BOX " + String(i) + ":" + String(BOX_COUNT[i]) + " ");
  }
  Serial.println("\n");


}
void PLAY_LCD(String parts, String Qty) {
  lcd.init();
  lcd.setCursor(0, 0);
  lcd.print(parts);
  lcd.setCursor(0, 1);
  lcd.print("QTY: " + Qty);
}
void PLAY_LCD_LOC(String Location, String Type) {
  lcd.init();
  lcd.setCursor(0, 0);
  lcd.print(Location);
  lcd.setCursor(0, 1);
  lcd.print(Type);
}
void PLAY_ERROR(String parts) {
  lcd.init();
  lcd.setCursor(0, 0);
  lcd.print(parts);
  lcd.setCursor(0, 1);
  lcd.print("Can not assign");
}
void PLAY_NEXT_TYPE() {
  int ct = 0;
  for (int i = 0 ; i < sizeof(LED_SW) / sizeof(LED_SW[0]) ; i++ ) {
    if (LED_SW[i] == 1) {
      ct += 1;
    }
  }

  for ( int i = 0 ; i < sizeof(chkList) / sizeof(chkList[0]) ; i++) {
    if (chkList[i][6] == "0") {
      delay(80);
      if (ct == 1) {
        PLAY_LCD(String(chkList[i][0]), String(chkList[i][1]));
      } else {
        PLAY_LCD_LOC(String(chkList[i][2]), String(chkList[i][0]));
      }
      
      //delay(3000);
      //PLAY_LCD(String(chkList[i][0]), String(chkList[i][1]));
      break;
    }
  }
  PLAY_COMPLETED();
}
void PLAY_COMPLETED() {
  int ct = 0;
  for (int i = 0 ; i < sizeof(checkBox) / sizeof(checkBox[0]) ; i++ ) {
    if (checkBox[i] == 1) {
      ct += 1;
    }
  }
  if (ct == 8) {
    lcd.init();
    lcd.setCursor(0, 0);
    lcd.print("ALL BOX DONE");
    lcd.setCursor(0, 1);
    lcd.print("GO BACK STATION");
  }
  //PLAY_COMPLETED();

}

void readInputValue(const String inputValue) {
  Serial.println("Parts User Entry: " + inputValue);
  Serial.println(sizeof(chkList) / sizeof(chkList[0])); // get row
  Serial.println(sizeof(chkList[0]) / sizeof(chkList[0][0])); // get column
  int ct = 0;
  for (int i = 0 ; i < sizeof(LED_SW) / sizeof(LED_SW[0]) ; i++ ) {
    if (LED_SW[i] == 1) {
      ct += 1;
    }
  }
  if (ct < 1 ) {
    for ( int i = 0 ; i < sizeof(chkList) / sizeof(chkList[0]) ; i++) {
      //Serial.println("Part: " + chkList[i][0]);

      if (chkList[i][0] == inputValue && chkList[i][6] == "0") {
        //chkList[i][5] = chkList[i][5].replace("BOX");
        int te = chkList[i][5].toInt();
        int j = i + 1;
        Serial.println("Get Parts in list row: "  + j);
        switch (te) {
          case 1:
            Serial.println("B1");
            setLedStatus(1);
            PLAY_LCD(String(chkList[i][0]), String(chkList[i][1]));
            break;
          case 2:
            Serial.println("B2");
            setLedStatus(2);
            PLAY_LCD(String(chkList[i][0]), String(chkList[i][1]));
            break;
          case 3:
            Serial.println("B3");
            setLedStatus(3);
            PLAY_LCD(String(chkList[i][0]), String(chkList[i][1]));
            break;
          case 4:
            Serial.println("B4");
            setLedStatus(4);
            PLAY_LCD(String(chkList[i][0]), String(chkList[i][1]));
            break;
          case 5:
            Serial.println("B5");
            setLedStatus(5);
            PLAY_LCD(String(chkList[i][0]), String(chkList[i][1]));
            break;
          case 6:
            Serial.println("B6");
            setLedStatus(6);
            PLAY_LCD(String(chkList[i][0]), String(chkList[i][1]));
            break;
          case 7:
            Serial.println("B7");
            setLedStatus(7);
            PLAY_LCD(String(chkList[i][0]), String(chkList[i][1]));
            break;
          case 8:
            Serial.println("B8");
            setLedStatus(8);
            PLAY_LCD(String(chkList[i][0]), String(chkList[i][1]));
            break;

        }
        break;
      } else {
        Serial.println("Can't find input");
      }
      //break;

    }
  } else {
    
    Serial.println("Can't assign new parts");
    PLAY_ERROR(inputValue);
    delay(2500);
    PLAY_NEXT_TYPE();
  }




}
void updateInputValue(const String inputValue) {
  Serial.println("Parts User Entry: " + inputValue);
  Serial.println(sizeof(chkList) / sizeof(chkList[0])); // get row
  Serial.println(sizeof(chkList[0]) / sizeof(chkList[0][0])); // get column
  int ct = 0;
  for (int i = 0 ; i < sizeof(LED_SW) / sizeof(LED_SW[0]) ; i++ ) {
    if (LED_SW[i] == 1) {
      ct += 1;
    }
  }
  delay(80);
  if (ct = 1 ) {
    for ( int i = 0 ; i < sizeof(chkList) / sizeof(chkList[0]) ; i++) {
      //Serial.println("Part: " + chkList[i][0]);

      if ((chkList[i][0] == inputValue) && (chkList[i][6] == "0")) {
        chkList[i][6] = "1";
        break;
      }
      //break;

    }
    delay(80);
    // clean BOX Completed item
    for (int i = 0 ; i < sizeof(BOX_Complete) / sizeof(BOX_Complete[0]) ; i++ ) {
      BOX_Complete[i] = 0;
      checkBox[i] = 0;
    }
    // Re Count BOX Completed item
    for (int i = 0 ; i < sizeof(chkList) / sizeof(chkList[0]) ; i++ ) {
      if (chkList[i][6] == "1") {
        int te = chkList[i][5].toInt();
        switch (te) {
          case 1:
            BOX_Complete[0] += 1;
            break;
          case 2:
            BOX_Complete[1] += 1;
            break;
          case 3:
            BOX_Complete[2] += 1;
            break;
          case 4:
            BOX_Complete[3] += 1;
            break;
          case 5:
            BOX_Complete[4] += 1;
            break;
          case 6:
            BOX_Complete[5] += 1;
            break;
          case 7:
            BOX_Complete[6] += 1;
            break;
          case 8:
            BOX_Complete[7] += 1;
            break;
        }
      }


    }
    

    for (int i = 0 ; i < sizeof(BOX_COUNT) / sizeof(BOX_COUNT[0])  ; i++ ) {
      if ((BOX_COUNT[i] == BOX_Complete[i] ) &&  (BOX_COUNT[i] > 0)) {
        
        LED_GE[i] = 1;
      }

      if ((BOX_COUNT[i] == BOX_Complete[i] ) ) {
        checkBox[i] = 1;
      }
    }

    for (int i = 0 ; i < sizeof(BOX_Complete) / sizeof(BOX_Complete[0])  ; i++ ) {
      Serial.print("BOX Comp" + String(i) + ":" + String(BOX_Complete[i]) + " ");
      //Serial.println("LED GE" + String(i) + ":" + String(LED_GE[i]));
    }
    Serial.println("\n");
    //delay(200);
    for (int i = 0 ; i < sizeof(BOX_COUNT) / sizeof(BOX_COUNT[0])  ; i++ ) {
      Serial.print("BOX Count" + String(i) + ":" + String(BOX_COUNT[i]) + " ");
      //Serial.println("LED GE" + String(i) + ":" + String(LED_GE[i]));
    }
    Serial.println("\n");
  } else {
    Serial.println("Can't assign new parts");
  }
  PLAY_NEXT_TYPE();
  //delay(200);
  openLedalert4ea();
  delay(200);
  
  
}

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  Serial.println("Hello, ESP32!");
  Serial.println(NUMPIXELS);


  Get_BOX_Count();
  // Startup function
  softStart();
  checkLedStatus();



  delay(1000);

  // check All localtion status
  Serial.println("Get led status");
  for ( int i = 0 ; i < (row * column) ; i ++) {

    Serial.print("LED " + String(i) + ":" + String(LED_SW[i]) + " ");
  }
  Serial.println("\n");
  Serial.println("Get led test");

  // when update led status re get all location status
  /*setLedStatus(4);
    //setLedStatus(7);
    checkLedStatus();
    Serial.println("Get led status");
    for ( int i = 0 ; i < (row * column) ; i ++) {

    Serial.println("LED " + String(i) + ":" + String(LED_SW[i]));
    }

    setLedStatus(8);
    checkLedStatus();
    Serial.println("Get led status");
    for ( int i = 0 ; i < (row * column) ; i ++) {

    Serial.println("LED " + String(i) + ":" + String(LED_SW[i]));
    }*/
  //openLedAlert(8);
  //openLedalert4ea(2);


  //openLedalert4ea(5);


}

void loop() {
  // put your main code here, to run repeatedly:
  //delay(10); // this speeds up the simulation


  if (Serial.available() ) {
    String command = Serial.readStringUntil('\n'); // read string until newline character

    Serial.println(command);
    readInputValue(command);

    intTemp = command;
    delay(80);
  }

  for ( int i = 0 ; i < sizeof(PUSH_BTN) ; i++) {
    if ( digitalRead(PUSH_BTN[i]) == LOW ) {
      //Serial.println("Get Press Num:" + String(PUSH_BTN[i]));
      Serial.println("inputValue Size :" + intTemp);
      Serial.println("inputValue Size :" + String(intTemp.length()));
      
      if (LED_SW[i] == 1) {
        
        if (intTemp.length() > 0) {
          updateInputValue(intTemp);
          intTemp = "";
          delay(200);
        }
        resetLedStatus(i + 1);
        delay(80);

        //break;
      }

    }
  }



  delay(20);


}