// GNP_TreeLamp
// 10 NeoPixel Ring 16/each
#include <LCD_I2C.h>
#include <Adafruit_NeoPixel.h>

LCD_I2C lcd(0x27, 16, 2); // Default address of most PCF8574 modules, change according

#define LED_PIN 13
#define LED_TOTAL_COUNT 160
Adafruit_NeoPixel strip(LED_TOTAL_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);  // 宣告 NeoPixel 物件,包含十組 LED
unsigned long previousMillis = 0;
unsigned long ADCpreviousMillis = 0;
unsigned long checkSwitchPreviousMillis = 0;

bool _serialDebugMode = false;   // true or false
unsigned long _breatheInterval = 10;
unsigned long _ADCInterval = 3000;
unsigned long _checkSwitchInterval = 1000;
int _prizeW1 = 10;
int _prizeY2 = 50;  // 欲設定的數值需手動加上_prizeW1取合 ex:40則為40+_prizeW1
int _prizeG3 = 50;
int _totalPrize = 100;
int _allUpSpeed = 20;  // g1 y2 r3 prize all lamp lighting all the way up
int _brightnessLimit = 255; // max is 255 , half is 125
int bS = 3; // breatheSpeed, led vaule step (0~255 step)
int _lampActiveSpeed = 50;  //放上杯子後繞一圈的燈速 delay time
int _allOffUpDelay = 2000 ; //整棵樹由下到上熄燈後等待多久回到呼吸燈
int _checkSwitchStateDelay = 10 ; // 檢查杯子是否有移開的delay time

int brightness[11] = {0, 25, 100, 200, 75, 250, 125, 50, 225, 150, 0};
int increment[11] = {bS, bS, bS, bS, bS, bS, bS, bS, bS, bS, bS};
int LED_SetStart[11] {0, 0, 16, 32, 48, 64, 80, 96, 112, 128, 144}; // 10 NeoPixel Ring 16/each
int LED_SetEnd[11] {0, 16, 32, 48, 64, 80, 96, 112, 128, 144, 160}; // 第0位址捨棄不用比較直觀
int swPin[10] { 32, 33, 25, 26, 27, 14, 12, 19, 18, 5}; //陣列位址從0算起

String TreeLampMode = "standyby";
byte sw1 = swPin[0]; byte sw2 = swPin[1]; byte sw3 = swPin[2]; byte sw4 = swPin[3];
byte sw5 = swPin[4]; byte sw6 = swPin[5]; byte sw7 = swPin[6]; byte sw8 = swPin[7];
byte sw9 = swPin[8]; byte sw10 = swPin[9];
bool sw1state = false; bool sw2state = false; bool sw3state = false; bool sw4state = false;
bool sw5state = false; bool sw6state = false; bool sw7state = false; bool sw8state = false;
bool sw9state = false; bool sw10state = false;

int _ADC1 = 4096;
int _ADC1map = 255;

int w1Count = 0; // 記錄g1的出現次數
int y2Count = 38; // 記錄y2的出現次數
int g3Count = 0; // 記錄r3的出現次數
int totalCount = 0;
String _countCode = "";

void setup() {
  strip.begin();
  Serial.begin(9600);
  // 初始化 NeoPixel
  for (int i = 0; i < 10; i++) {
    pinMode(swPin[i], INPUT_PULLUP);
  }
  // randomSeed(analogRead(A0)); // 設定亂數種子
  lcd.begin();
  lcd.backlight();
  // lcd.noBacklight();
  lcd.clear();
  lcd1602();

}

void loop() {
  unsigned long currentMillis = millis();
  unsigned long ADCcurrentMillis = millis();
  unsigned long checkSwitchCurrentMillis = millis();
  checkSwitch();

  // 呼叫呼吸燈函式
  if (TreeLampMode == "standyby") {
    if (currentMillis - previousMillis >= _breatheInterval) {
      previousMillis = currentMillis;
      breatheLED();        // 呼叫呼吸燈函式
    }
  }

  // 每秒檢查是否有杯子從杯架上移開
  if (checkSwitchCurrentMillis - checkSwitchPreviousMillis >= _checkSwitchInterval) {
    checkSwitchPreviousMillis = checkSwitchCurrentMillis;
    checkSwitchState();
  }

  // 每三秒檢查一次是否可變電阻1(樹燈亮度設定)有被改變
  if (ADCcurrentMillis - ADCpreviousMillis >= _ADCInterval) {
    ADCpreviousMillis = ADCcurrentMillis;
    _ADC1 = analogRead(36); // GIOP36
    _ADC1map = map(_ADC1, 0, 4095, 100, 255);
    // if (_serialDebugMode) Serial.print("ADC1map: ");
    // if (_serialDebugMode) Serial.print(_ADC1map);
    // if (_serialDebugMode) Serial.print("   _brightnessLimit: ");
    // if (_serialDebugMode) Serial.println(_brightnessLimit);
    lcd1602();
  }
}

void lcd1602() {
  lcd.setCursor(0, 0);
  lcd.print("Br:"); lcd.print(_brightnessLimit);
  lcd.print(" TOT:"); lcd.print(totalCount);
  lcd.setCursor(0, 1);
  lcd.print("W:"); lcd.print(w1Count); lcd.print(" y:"); lcd.print(y2Count);
  lcd.print(" g:"); lcd.print(g3Count); lcd.print(" ");
  lcd.print(_countCode); lcd.print("  ");
}

void randomPrize(int lampNum) {
  // 開始亂數抽獎
  // int randomNum = random(1, _totalPrize);

  int _randomFilterValue;

  if (w1Count <= 9 && y2Count <= 39 && g3Count <= 49) {
    _countCode = "all";
  }
  else if (w1Count >= 10 && y2Count <= 39 && g3Count <= 49) {
    _countCode = "a";
  }
  else if (w1Count <= 9 && y2Count >= 40 && g3Count <= 49) {
    _countCode = "b";
  }
  else if (w1Count <= 9 && y2Count <= 39 && g3Count >= 50) {
    _countCode = "c";
  }
  else if (w1Count >= 10 && y2Count >= 40 && g3Count <= 49) {
    _countCode = "ab";
  }
  else if (w1Count >= 10 && y2Count <= 39 && g3Count >= 50) {
    _countCode = "ac";
  }
  else if (w1Count <= 9 && y2Count >= 40 && g3Count >= 50) {
    _countCode = "bc";
  }
  else if (w1Count >= 10 && y2Count >= 40 && g3Count >= 50) {
    _countCode = "end";
  }


  if (_countCode == "all") {
    _randomFilterValue = random(1, 101);
  } else if (_countCode == "a") {
    _randomFilterValue = random(11, 101);
  } else if (_countCode == "b") {
    do {
      _randomFilterValue = random(1, 101);
    } while (_randomFilterValue >= 11 && _randomFilterValue <= 50);
    // int option = random(1, 3);
    // if (option == 1) {
    //   _randomFilterValue = random(1, 11);
    // } else {
    //   _randomFilterValue = random(51, 101);
    // }
  } else if (_countCode == "c") {
    _randomFilterValue = random(1, 51);
  } else if (_countCode == "ab") {
    _randomFilterValue = random(51, 101);
  } else if (_countCode == "ac") {
    _randomFilterValue = random(11, 51);
  } else if (_countCode == "bc") {
    _randomFilterValue = random(1, 11);
  } else {
    _randomFilterValue = random(51, 101);  // _countCode 不符合上述任何條件時跑三獎
    return;
  }

  if (_serialDebugMode) Serial.print("_randomFilterValue = ");
  if (_serialDebugMode) Serial.println(_randomFilterValue);
  if (_randomFilterValue <= _prizeW1) { // 如果隨機數字小於等於_prizeW1,則顯示頭獎
    w1Count ++ ;
    w1prizeshow(lampNum);  // 開始跑頭獎(白燈)流程

  } else if (_randomFilterValue <= _prizeY2) { // 如果隨機數字小於等於_prizeY2,則顯示二獎
    y2Count ++ ;
    y2prizeshow(lampNum);  //開始跑二獎(黃燈)流程

  } else {
    g3Count ++ ;
    g3prizeshow(lampNum);  // 其他情況開始跑三獎(綠燈)流程
  }
  totalCount = w1Count + y2Count + g3Count ;
  String Str_totalCount = String(totalCount);
  String Str_w1Count = String(w1Count);
  String Str_y2Count = String(y2Count);
  String Str_g3Count = String(g3Count);
  if (_serialDebugMode) Serial.print("w1=" + Str_w1Count + "  y2=" + Str_y2Count + "  g3=" + Str_g3Count);
  if (_serialDebugMode) Serial.println("  totalCount=" + Str_totalCount + "  countCode=" + _countCode);
}

void checkSwitch() {

  // check sw1
  if (digitalRead(sw1) == LOW && sw1state == false ) {
    TreeLampMode = "sw1";
    if (_serialDebugMode) Serial.println("press #1");
    sw1state = true;
    int lampNum = 1;  // this lampNum is sw1 been press(put cup)
    allLampOff();
    randomPrize(lampNum);
  }

  // check sw2
  if (digitalRead(sw2) == LOW && sw2state == false ) {
    TreeLampMode = "sw2";
    if (_serialDebugMode) Serial.println("press #2");
    sw2state = true;
    int lampNum = 2;  // this lampNum is sw1 been press(put cup)
    allLampOff();
    randomPrize(lampNum);
  }

  // check sw3
  if (digitalRead(sw3) == LOW && sw3state == false) {
    TreeLampMode = "sw3";
    if (_serialDebugMode) Serial.println("press #3");
    sw3state = true;
    int lampNum = 3;  // this lampNum is sw1 been press(put cup)
    allLampOff();
    randomPrize(lampNum);
  }

  // check sw4
  if (digitalRead(sw4) == LOW && sw4state == false ) {
    TreeLampMode = "sw4";
    if (_serialDebugMode) Serial.println("press #4");
    sw4state = true;
    int lampNum = 4;  // this lampNum is sw1 been press(put cup)
    allLampOff();
    randomPrize(lampNum);
  }

  // check sw5
  if (digitalRead(sw5) == LOW && sw5state == false) {
    TreeLampMode = "sw5";
    if (_serialDebugMode) Serial.println("press #5");
    sw5state = true;
    int lampNum = 5;  // this lampNum is sw1 been press(put cup)
    allLampOff();
    randomPrize(lampNum);
  }

  // check sw6
  if (digitalRead(sw6) == LOW && sw6state == false ) {
    TreeLampMode = "sw6";
    if (_serialDebugMode) Serial.println("press #6");
    sw6state = true;
    int lampNum = 6;  // this lampNum is sw1 been press(put cup)
    allLampOff();
    randomPrize(lampNum);
  }

  // check sw7
  if (digitalRead(sw7) == LOW && sw7state == false) {
    TreeLampMode = "sw7";
    if (_serialDebugMode) Serial.println("press #7");
    sw7state = true;
    int lampNum = 7;  // this lampNum is sw7 been press(put cup)
    allLampOff();
    randomPrize(lampNum);
  }

  // check sw8
  if (digitalRead(sw8) == LOW && sw8state == false ) {
    TreeLampMode = "sw8";
    if (_serialDebugMode) Serial.println("press #8");
    sw8state = true;
    int lampNum = 8;  // this lampNum is sw8 been press(put cup)
    allLampOff();
    randomPrize(lampNum);
  }

  // check sw9
  if (digitalRead(sw9) == LOW && sw9state == false) {
    TreeLampMode = "sw9";
    if (_serialDebugMode) Serial.println("press #9");
    sw9state = true;
    int lampNum = 9;  // this lampNum is sw9 been press(put cup)
    allLampOff();
    randomPrize(lampNum);
  }

  // check sw10
  if (digitalRead(sw10) == LOW && sw10state == false) {
    TreeLampMode = "sw10";
    if (_serialDebugMode) Serial.println("press #10");
    sw10state = true;
    int lampNum = 10;  // this lampNum is sw1 been press(put cup)
    allLampOff();
    randomPrize(lampNum);
  }
}

void checkSwitchState() {
  if (sw1state == true ) {
    if (digitalRead(sw1) == HIGH ) {
      sw1state = false;
      delay(_checkSwitchStateDelay);
    }
  }

  if (sw2state == true ) {
    if (digitalRead(sw2) == HIGH ) {
      sw2state = false;
      delay(_checkSwitchStateDelay);
    }
  }

  if (sw3state == true ) {
    if (digitalRead(sw3) == HIGH ) {
      sw3state = false;
      delay(_checkSwitchStateDelay);
    }
  }

  if (sw4state == true ) {
    if (digitalRead(sw4) == HIGH ) {
      sw4state = false;
      delay(_checkSwitchStateDelay);
    }
  }

  if (sw5state == true ) {
    if (digitalRead(sw5) == HIGH ) {
      sw5state = false;
      delay(_checkSwitchStateDelay);
    }
  }

  if (sw6state == true ) {
    if (digitalRead(sw6) == HIGH ) {
      sw6state = false;
      delay(_checkSwitchStateDelay);
    }
  }

  if (sw7state == true ) {
    if (digitalRead(sw7) == HIGH ) {
      sw7state = false;
      delay(_checkSwitchStateDelay);
    }
  }

  if (sw8state == true ) {
    if (digitalRead(sw8) == HIGH ) {
      sw8state = false;
      delay(_checkSwitchStateDelay);
    }
  }

  if (sw9state == true ) {
    if (digitalRead(sw9) == HIGH ) {
      sw9state = false;
      delay(_checkSwitchStateDelay);
    }
  }

  if (sw10state == true ) {
    if (digitalRead(sw10) == HIGH ) {
      sw10state = false;
      delay(_checkSwitchStateDelay);
    }
  }

  // if (digitalRead(sw1) == HIGH && sw1state == true ) {
  //   sw1state = false;
  //   delay(_checkSwitchStateDelay);
  // }
  // if (digitalRead(sw2) == HIGH && sw2state == true ) {
  //   sw2state = false;
  //   delay(_checkSwitchStateDelay);
  // }
  // if (digitalRead(sw3) == HIGH && sw3state == true ) {
  //   sw3state = false;
  //   delay(_checkSwitchStateDelay);
  // }
  // if (digitalRead(sw4) == HIGH && sw4state == true ) {
  //   sw4state = false;
  //   delay(_checkSwitchStateDelay);
  // }
  // if (digitalRead(sw5) == HIGH && sw5state == true ) {
  //   sw5state = false;
  //   delay(_checkSwitchStateDelay);
  // }
  // if (digitalRead(sw6) == HIGH && sw6state == true ) {
  //   sw6state = false;
  //   delay(_checkSwitchStateDelay);
  // }
  // if (digitalRead(sw7) == HIGH && sw7state == true ) {
  //   sw7state = false;
  //   delay(_checkSwitchStateDelay);
  // }
  // if (digitalRead(sw8) == HIGH && sw8state == true ) {
  //   sw8state = false;
  //   delay(_checkSwitchStateDelay);
  // }
  // if (digitalRead(sw9) == HIGH && sw9state == true ) {
  //   sw9state = false;
  //   delay(_checkSwitchStateDelay);
  // }
  // if (digitalRead(sw10) == HIGH && sw10state == true ) {
  //   sw10state = false;
  //   delay(_checkSwitchStateDelay);
  // }
}

void w1prizeshow(int lampSet) {
  // lamp 繞綠圈表示放入杯子
  for (int i = LED_SetStart[lampSet]; i < LED_SetEnd[lampSet]; i++) {
    strip.setPixelColor(i, strip.Color(0, _brightnessLimit, 0));
    strip.show();
    delay(_lampActiveSpeed);
  }
  allWhiteUp(lampSet);
}

void y2prizeshow(int lampSet) {
  // lamp 繞綠圈表示放入杯子
  for (int i = LED_SetStart[lampSet]; i < LED_SetEnd[lampSet]; i++) {
    strip.setPixelColor(i, strip.Color(0, _brightnessLimit, 0));
    strip.show();
    delay(_lampActiveSpeed);
  }
  allYellowUp(lampSet);
}

void g3prizeshow(int lampSet) {
  // lamp 繞綠圈表示放入杯子
  for (int i = LED_SetStart[lampSet]; i < LED_SetEnd[lampSet]; i++) {
    strip.setPixelColor(i, strip.Color(0, _brightnessLimit, 0));
    strip.show();
    delay(_lampActiveSpeed);
  }
  allGreenUp(lampSet);
}

void allWhiteUp(int exclude) {
  // 一組一組往上亮,漸層感差,時間也拖太久
  for (int w = 10; w > 0; w--) {
    // if (w == exclude) {
    //   continue; // 跳過指定的exclude,繼續下一個迴圈
    // }
    for (int b = 0; b < _brightnessLimit; b = b + _allUpSpeed) {
      for (int i = LED_SetStart[w]; i < LED_SetEnd[w]; i++) {
        strip.setPixelColor(i, strip.Color(b, b, b));
      }
      strip.show();
    }
  }
  allWhiteOffUp(exclude);
}

void allWhiteOffUp(int exclude) {
  // 一組一組往上亮,漸層感差,時間也拖太久
  for (int w = 10; w > 0; w--) {
    if (w == exclude) {
      continue; // 跳過指定的exclude,繼續下一個迴圈
    }
    for (int b = _brightnessLimit; b > 0; b = b - _allUpSpeed) {
      for (int i = LED_SetStart[w]; i < LED_SetEnd[w]; i++) {
        strip.setPixelColor(i, strip.Color(b, b, b));
      }
      strip.show();
    }
  }
  delay(_allOffUpDelay);
  TreeLampMode = "standyby";
}

void allYellowUp(int exclude) {
  // 一組一組往上亮,漸層感差,時間也拖太久
  for (int w = 10; w > 0; w--) {
    // if (w == exclude) {
    //   continue; // 跳過指定的exclude,繼續下一個迴圈
    // }
    for (int b = 0; b < _brightnessLimit; b = b + _allUpSpeed) {
      for (int i = LED_SetStart[w]; i < LED_SetEnd[w]; i++) {
        strip.setPixelColor(i, strip.Color(b, b, 0));
      }
      strip.show();
    }
  }
  allYellowOffUp(exclude);
}

void allYellowOffUp(int exclude) {
  // 一組一組往上亮,漸層感差,時間也拖太久
  for (int w = 10; w > 0; w--) {
    if (w == exclude) {
      continue; // 跳過指定的exclude,繼續下一個迴圈
    }
    for (int b = _brightnessLimit; b > 0; b = b - _allUpSpeed) {
      for (int i = LED_SetStart[w]; i < LED_SetEnd[w]; i++) {
        strip.setPixelColor(i, strip.Color(b, b, 0));
      }
      strip.show();
    }
  }
  delay(_allOffUpDelay);
  TreeLampMode = "standyby";
}

void allGreenUp(int exclude) {
  // 一組一組往上亮,漸層感差,時間也拖太久
  for (int w = 10; w > 0; w--) {
    // if (w == exclude) {
    //   continue; // 跳過指定的exclude,繼續下一個迴圈
    // }
    for (int b = 0; b < _brightnessLimit; b = b + _allUpSpeed) {
      for (int i = LED_SetStart[w]; i < LED_SetEnd[w]; i++) {
        strip.setPixelColor(i, strip.Color(0, b, 0));
      }
      strip.show();
    }
  }
  allGreenOffUp(exclude);
}

void allGreenOffUp(int exclude) {
  // 一組一組往上亮,漸層感差,時間也拖太久
  for (int w = 10; w > 0; w--) {
    if (w == exclude) {
      continue; // 跳過指定的exclude,繼續下一個迴圈
    }
    for (int b = _brightnessLimit; b > 0; b = b - _allUpSpeed) {
      for (int i = LED_SetStart[w]; i < LED_SetEnd[w]; i++) {
        strip.setPixelColor(i, strip.Color(0, b, 0));
      }
      strip.show();
    }
  }
  delay(_allOffUpDelay);
  TreeLampMode = "standyby";
}

void allLampOff() {
  for (int i = 0; i < LED_TOTAL_COUNT; i++) {
    strip.setPixelColor(i, strip.Color(0, 0, 0));
  }
  strip.show();
  delay(300);
}

void LampSelectOff(int LampSelect) {
  switch (LampSelect) {
    case 0:
      break;
    case 1:
      for (int b = 0; b < _brightnessLimit; b = b + _allUpSpeed) {
        for (int i = LED_SetStart[1]; i < LED_SetEnd[1]; i++) {
          strip.setPixelColor(i, strip.Color(0, 0, 0));
        }
        strip.show();
      }
      break;
    case 2:
      for (int b = 0; b < _brightnessLimit; b = b + _allUpSpeed) {
        for (int i = LED_SetStart[2]; i < LED_SetEnd[2]; i++) {
          strip.setPixelColor(i, strip.Color(0, 0, 0));
        }
        strip.show();
      }
      break;
    case 3:
      for (int b = 0; b < _brightnessLimit; b = b + _allUpSpeed) {
        for (int i = LED_SetStart[3]; i < LED_SetEnd[3]; i++) {
          strip.setPixelColor(i, strip.Color(0, 0, 0));
        }
        strip.show();
      }
      break;
    case 4:
      for (int b = 0; b < _brightnessLimit; b = b + _allUpSpeed) {
        for (int i = LED_SetStart[4]; i < LED_SetEnd[4]; i++) {
          strip.setPixelColor(i, strip.Color(0, 0, 0));
        }
        strip.show();
      }
      break;
    case 5:
      for (int b = 0; b < _brightnessLimit; b = b + _allUpSpeed) {
        for (int i = LED_SetStart[5]; i < LED_SetEnd[5]; i++) {
          strip.setPixelColor(i, strip.Color(0, 0, 0));
        }
        strip.show();
      }
      break;
    case 6:
      for (int b = 0; b < _brightnessLimit; b = b + _allUpSpeed) {
        for (int i = LED_SetStart[6]; i < LED_SetEnd[6]; i++) {
          strip.setPixelColor(i, strip.Color(0, 0, 0));
        }
        strip.show();
      }
      break;
    case 7:
      for (int b = 0; b < _brightnessLimit; b = b + _allUpSpeed) {
        for (int i = LED_SetStart[7]; i < LED_SetEnd[7]; i++) {
          strip.setPixelColor(i, strip.Color(0, 0, 0));
        }
        strip.show();
      }
      break;
    case 8:
      for (int b = 0; b < _brightnessLimit; b = b + _allUpSpeed) {
        for (int i = LED_SetStart[8]; i < LED_SetEnd[8]; i++) {
          strip.setPixelColor(i, strip.Color(0, 0, 0));
        }
        strip.show();
      }
      break;
    case 9:
      for (int b = 0; b < _brightnessLimit; b = b + _allUpSpeed) {
        for (int i = LED_SetStart[9]; i < LED_SetEnd[9]; i++) {
          strip.setPixelColor(i, strip.Color(0, 0, 0));
        }
        strip.show();
      }
      break;
    case 10:
      for (int b = 0; b < _brightnessLimit; b = b + _allUpSpeed) {
        for (int i = LED_SetStart[10]; i < LED_SetEnd[10]; i++) {
          strip.setPixelColor(i, strip.Color(0, 0, 0));
        }
        strip.show();
      }
      break;
  }
}

void breatheLED() {
  if (_brightnessLimit >= _ADC1map) _brightnessLimit = _brightnessLimit - 1;
  if (_brightnessLimit <= _ADC1map) _brightnessLimit = _brightnessLimit + 1;

  for (int i = 1 ; i < 11 ; i++) {  // 亮度遞增(或遞減)
    brightness[i] = brightness[i] + increment[i];
  }

  for (int i = 1 ; i < 11 ; i++) {  // 判斷亮度是否小於0或大於上限,如是,反向
    if (brightness[i] <= 0 ) {
      brightness[i] = 0;
      increment[i] = -increment[i];
    }
    if (brightness[i] >= _brightnessLimit) {
      brightness[i] = _brightnessLimit;
      increment[i] = -increment[i];
    }
  }

  for (int q = 1 ; q < 11; q ++) { // q是10個燈組
    for (int i = LED_SetStart[q]; i < LED_SetEnd[q]; i++) {
      strip.setPixelColor(i, strip.Color(0, brightness[q], 0));
    }
  }
  strip.show();
}