// GNP_TreeLamp
// 10 NeoPixel Ring 16/each

#include <Adafruit_NeoPixel.h>
#define LED_PIN 12
#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 breatheInterval = 5;
int prizeG1 = 10;
int prizeG2 = 30;  // 欲設定的數值需手動加上prizeG1取合 ex:20則為20+prizeG1
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 = 1; // breatheSpeed, led vaule step (0~255 step)
int r3bS = 1; //r3breatheSpeed, led vaule step (0~255 step)
int lampActiveSpeed = 10;  //when cup put at lamp,ring light delay time
int allOffUpDelay = 3000 ; //整棵樹由下到上熄燈後等待多久回到呼吸燈

int brightness[11] = {0, 25, 100, 200, 75, 250, 125, 50, 225, 150, 0};
int r3brightness[11] = {-1000, -900, -800, -700, -600, -500, -400, -300, -200, -100, 0};
int increment[11] = {bS, bS, bS, bS, bS, bS, bS, bS, bS, bS, bS};
int r3increment[11] = {r3bS, r3bS, r3bS, r3bS, r3bS, r3bS, r3bS, r3bS, r3bS, r3bS, r3bS};
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] {2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; //陣列位址從0算起
// 25 50 75 100 125 150 175 200 225 250
String TreeLampMode = "standyby";
byte sw1 = swPin[9]; byte sw2 = swPin[0]; byte sw3 = swPin[1]; byte sw4 = swPin[2];
byte sw5 = swPin[3]; byte sw6 = swPin[4]; byte sw7 = swPin[5]; byte sw8 = swPin[6];
byte sw9 = swPin[7]; byte sw10 = swPin[8];
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 g1Count = 0; // 記錄g1的出現次數
int y2Count = 0; // 記錄y2的出現次數
int r3Count = 0; // 記錄r3的出現次數



void setup() {
  strip.begin();
  Serial.begin(9600);
  // 初始化 NeoPixel
  for (int i = 0; i < 10; i++) {
    pinMode(swPin[i], INPUT_PULLUP);
  }
}

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

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

void checkSwitch() {

  // check sw1
  if (digitalRead(sw1) == LOW && sw1state == false ) {
    TreeLampMode = "sw1";
    sw1state = true;
    int lampNum = 1;  // this lampNum is sw1 been press(put cup)
    allLampOff();

    // 開始亂數抽獎
    int randomNum = random(1, totalPrize);
    // Serial.println(randomNum);
    if (randomNum <= prizeG1) { // 如果隨機數字小於等於prizeG1,則顯示頭獎
      g1Count ++ ;
      g1prizeshow(lampNum);

    } else if (randomNum <= prizeG2) { // 如果隨機數字小於等於prizeG2,則顯示二獎
      y2Count ++ ;
      y2prizeshow(lampNum);

    } else { // 其他情況顯示三獎
      r3Count ++ ;
      r3prizeshow(lampNum);
    }
  }

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

    // 開始亂數抽獎
    int randomNum = random(1, totalPrize);
    // Serial.println(randomNum);
    if (randomNum <= prizeG1) { // 如果隨機數字小於等於prizeG1,則顯示頭獎
      g1Count ++ ;
      g1prizeshow(lampNum);

    } else if (randomNum <= prizeG2) { // 如果隨機數字小於等於prizeG2,則顯示二獎
      y2Count ++ ;
      y2prizeshow(lampNum);

    } else { // 其他情況顯示三獎
      r3Count ++ ;
      r3prizeshow(lampNum);
    }
  }

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

    // 開始亂數抽獎
    int randomNum = random(1, totalPrize);
    // Serial.println(randomNum);
    if (randomNum <= prizeG1) { // 如果隨機數字小於等於prizeG1,則顯示頭獎
      g1Count ++ ;
      g1prizeshow(lampNum);

    } else if (randomNum <= prizeG2) { // 如果隨機數字小於等於prizeG2,則顯示二獎
      y2Count ++ ;
      y2prizeshow(lampNum);

    } else { // 其他情況顯示三獎
      r3Count ++ ;
      r3prizeshow(lampNum);
    }
  }

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

    // 開始亂數抽獎
    int randomNum = random(1, totalPrize);
    // Serial.println(randomNum);
    if (randomNum <= prizeG1) { // 如果隨機數字小於等於prizeG1,則顯示頭獎
      g1Count ++ ;
      g1prizeshow(lampNum);

    } else if (randomNum <= prizeG2) { // 如果隨機數字小於等於prizeG2,則顯示二獎
      y2Count ++ ;
      y2prizeshow(lampNum);

    } else { // 其他情況顯示三獎
      r3Count ++ ;
      r3prizeshow(lampNum);
    }
  }

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

    // 開始亂數抽獎
    int randomNum = random(1, totalPrize);
    // Serial.println(randomNum);
    if (randomNum <= prizeG1) { // 如果隨機數字小於等於prizeG1,則顯示頭獎
      g1Count ++ ;
      g1prizeshow(lampNum);

    } else if (randomNum <= prizeG2) { // 如果隨機數字小於等於prizeG2,則顯示二獎
      y2Count ++ ;
      y2prizeshow(lampNum);

    } else { // 其他情況顯示三獎
      r3Count ++ ;
      r3prizeshow(lampNum);
    }
  }

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

    // 開始亂數抽獎
    int randomNum = random(1, totalPrize);
    // Serial.println(randomNum);
    if (randomNum <= prizeG1) { // 如果隨機數字小於等於prizeG1,則顯示頭獎
      g1Count ++ ;
      g1prizeshow(lampNum);

    } else if (randomNum <= prizeG2) { // 如果隨機數字小於等於prizeG2,則顯示二獎
      y2Count ++ ;
      y2prizeshow(lampNum);

    } else { // 其他情況顯示三獎
      r3Count ++ ;
      r3prizeshow(lampNum);
    }
  }

  // check sw7
  if (digitalRead(sw7) == LOW && sw7state == false) {
    TreeLampMode = "sw7";
    sw7state = true;
    int lampNum = 7;  // this lampNum is sw7 been press(put cup)
    allLampOff();

    // 開始亂數抽獎
    int randomNum = random(1, totalPrize);
    // Serial.println(randomNum);
    if (randomNum <= prizeG1) { // 如果隨機數字小於等於prizeG1,則顯示頭獎
      g1Count ++ ;
      g1prizeshow(lampNum);

    } else if (randomNum <= prizeG2) { // 如果隨機數字小於等於prizeG2,則顯示二獎
      y2Count ++ ;
      y2prizeshow(lampNum);

    } else { // 其他情況顯示三獎
      r3Count ++ ;
      r3prizeshow(lampNum);
    }
  }

  // check sw8
  if (digitalRead(sw8) == LOW && sw8state == false ) {
    TreeLampMode = "sw8";
    sw8state = true;
    int lampNum = 8;  // this lampNum is sw8 been press(put cup)
    allLampOff();

    // 開始亂數抽獎
    int randomNum = random(1, totalPrize);
    // Serial.println(randomNum);
    if (randomNum <= prizeG1) { // 如果隨機數字小於等於prizeG1,則顯示頭獎
      g1Count ++ ;
      g1prizeshow(lampNum);

    } else if (randomNum <= prizeG2) { // 如果隨機數字小於等於prizeG2,則顯示二獎
      y2Count ++ ;
      y2prizeshow(lampNum);

    } else { // 其他情況顯示三獎
      r3Count ++ ;
      r3prizeshow(lampNum);
    }
  }

  // check sw9
  if (digitalRead(sw9) == LOW && sw9state == false) {
    TreeLampMode = "sw9";
    sw9state = true;
    int lampNum = 9;  // this lampNum is sw9 been press(put cup)
    allLampOff();

    // 開始亂數抽獎
    int randomNum = random(1, totalPrize);
    // Serial.println(randomNum);
    if (randomNum <= prizeG1) { // 如果隨機數字小於等於prizeG1,則顯示頭獎
      g1Count ++ ;
      g1prizeshow(lampNum);

    } else if (randomNum <= prizeG2) { // 如果隨機數字小於等於prizeG2,則顯示二獎
      y2Count ++ ;
      y2prizeshow(lampNum);

    } else { // 其他情況顯示三獎
      r3Count ++ ;
      r3prizeshow(lampNum);
    }
  }

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

    // 開始亂數抽獎
    int randomNum = random(1, totalPrize);
    // Serial.println(randomNum);
    if (randomNum <= prizeG1) { // 如果隨機數字小於等於prizeG1,則顯示頭獎
      g1Count ++ ;
      g1prizeshow(lampNum);

    } else if (randomNum <= prizeG2) { // 如果隨機數字小於等於prizeG2,則顯示二獎
      y2Count ++ ;
      y2prizeshow(lampNum);

    } else { // 其他情況顯示三獎
      r3Count ++ ;
      r3prizeshow(lampNum);
    }
  }
}

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

void g1prizeshow(int lampSet) {
  // lamp1 繞綠圈表示頭獎
  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 y2prizeshow(int lampSet) {
  // lamp1 繞黃圈表示二獎
  for (int i = LED_SetStart[lampSet]; i < LED_SetEnd[lampSet]; i++) {
    strip.setPixelColor(i, strip.Color(brightnessLimit, brightnessLimit, 0));
    strip.show();
    delay(lampActiveSpeed);
  }
  allYellowUp(lampSet);
}

void r3prizeshow(int lampSet) {
  // lamp1 繞紅圈表示三獎
  for (int i = LED_SetStart[lampSet]; i < LED_SetEnd[lampSet]; i++) {
    strip.setPixelColor(i, strip.Color(brightnessLimit, 0, 0));
    strip.show();
    delay(lampActiveSpeed);
  }
  allRedUp(lampSet);
}

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 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 allRedUp(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, 0, 0));
      }
      strip.show();
    }
  }
  allRedOffUp(exclude);
}

void allRedOffUp(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, 0, 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(100);
}

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() {
  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] >= 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();
}