// https://forum.arduino.cc/t/issue-with-matrix-keypad-vs-pull-up-buttons-in-the-code/1239164
// https://wokwi.com/projects/393248438299541505

# include <EEPROM.h>
# include <Keypad.h>

// hack it to use a strip of neopixels
//
# define NINE   8   // # of LEDs to handle (lose status LED at 13)
# define BASE   5   // base. pins must++

# include <Adafruit_NeoPixel.h>

# define LED_PIN    A0
# define LED_COUNT  NINE

Adafruit_NeoPixel disaply(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);

void myDigitalWrite(int theLED, int theValue)
{

  unsigned long was = disaply.getPixelColor(theLED - BASE);

  disaply.setPixelColor(theLED - BASE, theValue ? 0xff0000 : 0x202020);
  disaply.show();

  return;   // rest is for 

  if (was == disaply.getPixelColor(theLED - BASE)) Serial.println("                         work to do");

  Serial.print(theLED);
  Serial.print(" + ");

  bool any = false;
  for (int ii = 0; ii < 9; ii++)
    any |= disaply.getPixelColor(ii) == 0xff0000;

//  if (any) {
  {
    for (int ii = 0; ii < 9; ii++)
      Serial.print(disaply.getPixelColor(ii) == 0xff0000 ? "X" : ".");
  
    Serial.println("");
  }
}

# define digitalWrite myDigitalWrite
//
// end of hack. sue me, I said it was a hack

// the rest is mostly untouched original

const byte ROWS = 2;
const byte COLS = 3;
const byte key [ROWS][COLS] = 
{
  {1,2,3},
  {4,5,6}
};

const String ButtonPress[6] = {"Stop", "Warn", "Change", "Left", "Center", "Right"};

byte rowPins[ROWS] = {3, 2};
byte colPins[COLS] = {A2, A3, A4};

bool gotKey = false;

byte pressedKey;

Keypad keypad = Keypad(makeKeymap(key),rowPins, colPins, ROWS, COLS);

int statuslight = 13;
int LEDleft[] = {5, 6, 7, 8, 9, 10, 11, 12};
int LEDright[] = {12, 11, 10, 9, 8, 7, 6, 5};
int centerleft[] = {9, 10, 11, 12};
int centerright[] = {8, 7, 6, 5};
int light = 0;
int counter = 1;
int pattern_count = 0;
int warning_count = EEPROM.read(0);
long lasttimer = 0;
static long timer = 100;
static long timer2 = 200;
#define LEFTside 0x0
#define RIGHTside 0x1
byte whichLED = LEFTside;
byte LEFT_state = LOW;
byte RIGHT_state = LOW;
byte arrow_state = HIGH;
unsigned long strobeDelay = 75;
unsigned long switchDelay = 500;
unsigned long switchDelay2 = 1000;
unsigned long switchDelay3 = 450;
unsigned long strobeWait = strobeDelay;
unsigned long waitUntilSwitch = switchDelay;
unsigned long sequenceStartTime;
unsigned long sequenceStartTime2;

void setup() {
  Serial.begin(9600);

  disaply.begin();
  disaply.setPixelColor(1, 0xff40c0);
  disaply.show();
  delay(777);
  disaply.clear();  
  disaply.show();

  pinMode(statuslight, OUTPUT);
  pinMode(12, OUTPUT);
  pinMode(11, OUTPUT);
  pinMode(10, OUTPUT);
  pinMode(9, OUTPUT);
  pinMode(8, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(5, OUTPUT);

}
void loop() {

//  digitalWrite(statuslight, HIGH);

  byte key = (byte)keypad.getKey();
  if (key) {
    Serial.print("\n$raw key "); Serial.print(key);
    gotKey = true;
    pressedKey = key - 1;
    key = 0;
  }
  if (gotKey == true) {
    Serial.print("  "); Serial.print("now key "); Serial.println(pressedKey); Serial.print("  $ ");
    Serial.println(ButtonPress[pressedKey]);
    gotKey = false;

    /*}
    if (0) {*/

    if (1) // hand control this outlier
      if (ButtonPress[pressedKey] == "Change") {
        delay(500);
        warning_count++;
        if (warning_count >= 18) {
          warning_count = 1;
        }
        // already is boss      gotKey = false;
      }

    if (ButtonPress[pressedKey] == "Right") {
      delay(50);
      pattern_count = 1;
    }

    if (ButtonPress[pressedKey] == "Center") {
      delay(50);
      pattern_count = 2;
    }

    if (ButtonPress[pressedKey] == "Left") {
      delay(50);
      pattern_count = 3;
    }

    if (ButtonPress[pressedKey] == "Warn") {
      delay(50);
      pattern_count = 4;
    }

    if (ButtonPress[pressedKey] == "Stop") {
      delay(50);
      pattern_count = 0;
      EEPROM.update(0, warning_count);
    }
  }

  static int lastPattern = -1;
  if (pattern_count != lastPattern) {
    Serial.print("pattern_count case "); Serial.println(pattern_count);
    lastPattern = pattern_count;
  }


if (1)
  switch (pattern_count) {
    case 0:
      pattern_off();
      break;
    case 1:
      traffic_left();
Serial.println("            traffic_left");
      break;
    case 2:
      traffic_center();
      break;
    case 3:
      traffic_right();
      break;
    case 4:
      traffic_warning();
      break;
  }

}

void pattern_off() {
  for (int i = 0; i <= 7; i++) {
    digitalWrite(LEDright[i], LOW);
  }
}

void traffic_left() {
  long time = millis() - sequenceStartTime;
  if (time < 16000)
  {
    left_arrow();
  }
  else if (time < 18000)
  {
    half_half_flash();
  }
  else sequenceStartTime = millis();
}

void traffic_center() {
  long time = millis() - sequenceStartTime;
  if (time < 16000)
  {
    center_arrow();
  }
  else if (time < 18000)
  {
    half_half_flash();
  }
  else sequenceStartTime = millis();
}

void traffic_right() {
  long time = millis() - sequenceStartTime;
  if (time < 16000)
  {
    right_arrow();
  }
  else if (time < 18000)
  {
    half_half_flash();
  }
  else sequenceStartTime = millis();
}

void traffic_warning() {
  switch (warning_count) {
    case 1:
      even_odd();
      break;
    case 2:
      even_odd_flash();
      break;
    case 3:
      half_half();
      break;
    case 4:
      half_half_flash();
      break;
    case 5:
      two_by_two();
      break;
    case 6:
      tow_by_two_flash();
      break;
    case 7:
      two_by_two_parallel();
      break;
    case 8:
      two_by_two_parallel_flash();
      break;
    case 9:
      three_by_one();
      break;
    case 10:
      three_by_one_flash();
      break;
    case 11:
      outboard();
      break;
    case 12:
      outboard_flash();
      break;
    case 13:
      inboard_6();
      break;
    case 14:
      inboard_6_flash();
      break;
    case 15:
      solid();
      break;
    case 16:
      solid_flash();
      break;
    case 17:
      solid_flash_pause();
      break;
    case 18:
      multi_pattern();
      break;
  }
}

void even_odd() {
  for (int i = 0; i <= 7; i++) {
    digitalWrite(LEDright[i], LOW);
  }
  long time = millis() - sequenceStartTime;
  if (time < 300)
  {
    digitalWrite(12, HIGH);
    digitalWrite(11, LOW);
    digitalWrite(10, HIGH);
    digitalWrite(9, LOW);
    digitalWrite(8, HIGH);
    digitalWrite(7, LOW);
    digitalWrite(6, HIGH);
    digitalWrite(5, LOW);
  }
  else if (time < 600)
  {
    digitalWrite(12, LOW);
    digitalWrite(11, HIGH);
    digitalWrite(10, LOW);
    digitalWrite(9, HIGH);
    digitalWrite(8, LOW);
    digitalWrite(7, HIGH);
    digitalWrite(6, LOW);
    digitalWrite(5, HIGH);
  }
  else sequenceStartTime = millis();
}
void even_odd_flash() {
  for (int i = 0; i <= 7; i++) {
    digitalWrite(LEDright[i], LOW);
  }
  digitalWrite(12, LEFT_state);
  digitalWrite(11, RIGHT_state);
  digitalWrite(10, LEFT_state);
  digitalWrite(9, RIGHT_state);
  digitalWrite(8, LEFT_state);
  digitalWrite(7, RIGHT_state);
  digitalWrite(6, LEFT_state);
  digitalWrite(5, RIGHT_state);
  if ((long)(millis() - waitUntilSwitch) >= 0) {
    LEFT_state = LOW;
    RIGHT_state = LOW;
    whichLED = !whichLED;
    waitUntilSwitch += switchDelay;
  }
  if ((long)(millis() - strobeWait) >= 0) {
    if (whichLED == LEFTside)
      LEFT_state = !LEFT_state;
    if (whichLED == RIGHTside)
      RIGHT_state = !RIGHT_state;
    strobeWait += strobeDelay;
  }
}

void half_half() {
  for (int i = 0; i <= 7; i++) {
    digitalWrite(LEDright[i], LOW);
  }
  long time = millis() - sequenceStartTime;
  if (time < 250)
  {
    digitalWrite(12, HIGH);
    digitalWrite(11, HIGH);
    digitalWrite(10, HIGH);
    digitalWrite(9, HIGH);
    digitalWrite(8, LOW);
    digitalWrite(7, LOW);
    digitalWrite(6, LOW);
    digitalWrite(5, LOW);
  }
  else if (time < 500)
  {
    digitalWrite(12, LOW);
    digitalWrite(11, LOW);
    digitalWrite(10, LOW);
    digitalWrite(9, LOW);
    digitalWrite(8, HIGH);
    digitalWrite(7, HIGH);
    digitalWrite(6, HIGH);
    digitalWrite(5, HIGH);
  }
  else sequenceStartTime = millis();
}
void half_half_flash() {
  for (int i = 0; i <= 7; i++) {
    digitalWrite(LEDright[i], LOW);
  }
  digitalWrite(12, LEFT_state);
  digitalWrite(11, LEFT_state);
  digitalWrite(10, LEFT_state);
  digitalWrite(9, LEFT_state);
  digitalWrite(8, RIGHT_state);
  digitalWrite(7, RIGHT_state);
  digitalWrite(6, RIGHT_state);
  digitalWrite(5, RIGHT_state);
  if ((long)(millis() - waitUntilSwitch) >= 0) {
    LEFT_state = LOW;
    RIGHT_state = LOW;
    whichLED = !whichLED;
    waitUntilSwitch += switchDelay;
  }
  if ((long)(millis() - strobeWait) >= 0) {
    if (whichLED == LEFTside)
      LEFT_state = !LEFT_state;
    if (whichLED == RIGHTside)
      RIGHT_state = !RIGHT_state;
    strobeWait += strobeDelay;
  }
}

void two_by_two() {
  for (int i = 0; i <= 7; i++) {
    digitalWrite(LEDright[i], LOW);
  }
  long time = millis() - sequenceStartTime;
  if (time < 150)
  {
    digitalWrite(12, HIGH);
    digitalWrite(11, HIGH);
    digitalWrite(10, LOW);
    digitalWrite(9, LOW);
    digitalWrite(8, LOW);
    digitalWrite(7, LOW);
    digitalWrite(6, HIGH);
    digitalWrite(5, HIGH);
  }
  else if (time < 300)
  {
    digitalWrite(12, LOW);
    digitalWrite(11, LOW);
    digitalWrite(10, HIGH);
    digitalWrite(9, HIGH);
    digitalWrite(8, HIGH);
    digitalWrite(7, HIGH);
    digitalWrite(6, LOW);
    digitalWrite(5, LOW);
  }
  else sequenceStartTime = millis();
}

void tow_by_two_flash() {
  for (int i = 0; i <= 7; i++) {
    digitalWrite(LEDright[i], LOW);
  }
  digitalWrite(12, LEFT_state);
  digitalWrite(11, LEFT_state);
  digitalWrite(10, RIGHT_state);
  digitalWrite(9, RIGHT_state);
  digitalWrite(8, RIGHT_state);
  digitalWrite(7, RIGHT_state);
  digitalWrite(6, LEFT_state);
  digitalWrite(5, LEFT_state);
  if ((long)(millis() - waitUntilSwitch) >= 0) {
    LEFT_state = LOW;
    RIGHT_state = LOW;
    whichLED = !whichLED;
    waitUntilSwitch += switchDelay;
  }
  if ((long)(millis() - strobeWait) >= 0) {
    if (whichLED == LEFTside)
      LEFT_state = !LEFT_state;
    if (whichLED == RIGHTside)
      RIGHT_state = !RIGHT_state;
    strobeWait += strobeDelay;
  }
}

void three_by_one() {
  for (int i = 0; i <= 7; i++) {
    digitalWrite(LEDright[i], LOW);
  }
  long time = millis() - sequenceStartTime;
  if (time < 400)
  {
    digitalWrite(12, HIGH);
    digitalWrite(11, HIGH);
    digitalWrite(10, HIGH);
    digitalWrite(9, LOW);
    digitalWrite(8, HIGH);
    digitalWrite(7, LOW);
    digitalWrite(6, LOW);
    digitalWrite(5, LOW);
  }
  else if (time < 800)
  {
    digitalWrite(12, LOW);
    digitalWrite(11, LOW);
    digitalWrite(10, LOW);
    digitalWrite(9, HIGH);
    digitalWrite(8, LOW);
    digitalWrite(7, HIGH);
    digitalWrite(6, HIGH);
    digitalWrite(5, HIGH);
  }
  else sequenceStartTime = millis();
}

void three_by_one_flash() {
  for (int i = 0; i <= 7; i++) {
    digitalWrite(LEDright[i], LOW);
  }
  digitalWrite(12, RIGHT_state);
  digitalWrite(11, RIGHT_state);
  digitalWrite(10, RIGHT_state);
  digitalWrite(8, RIGHT_state);
  digitalWrite(9, LEFT_state);
  digitalWrite(7, LEFT_state);
  digitalWrite(6, LEFT_state);
  digitalWrite(5, LEFT_state);
  if ((long)(millis() - waitUntilSwitch) >= 0) {
    LEFT_state = LOW;
    RIGHT_state = LOW;
    whichLED = !whichLED;
    waitUntilSwitch += switchDelay;
  }
  if ((long)(millis() - strobeWait) >= 0) {
    if (whichLED == LEFTside)
      LEFT_state = !LEFT_state;
    if (whichLED == RIGHTside)
      RIGHT_state = !RIGHT_state;
    strobeWait += strobeDelay;
  }
}

void two_by_two_parallel() {
  for (int i = 0; i <= 7; i++) {
    digitalWrite(LEDright[i], LOW);
  }
  long time = millis() - sequenceStartTime;
  if (time < 150)
  {
    digitalWrite(12, HIGH);
    digitalWrite(11, HIGH);
    digitalWrite(10, LOW);
    digitalWrite(9, LOW);
    digitalWrite(8, HIGH);
    digitalWrite(7, HIGH);
    digitalWrite(6, LOW);
    digitalWrite(5, LOW);
  }
  else if (time < 300)
  {
    digitalWrite(12, LOW);
    digitalWrite(11, LOW);
    digitalWrite(10, HIGH);
    digitalWrite(9, HIGH);
    digitalWrite(8, LOW);
    digitalWrite(7, LOW);
    digitalWrite(6, HIGH);
    digitalWrite(5, HIGH);
  }
  else sequenceStartTime = millis();
}

void two_by_two_parallel_flash() {
  for (int i = 0; i <= 7; i++) {
    digitalWrite(LEDright[i], LOW);
  }
  digitalWrite(12, LEFT_state);
  digitalWrite(11, LEFT_state);
  digitalWrite(10, RIGHT_state);
  digitalWrite(9, RIGHT_state);
  digitalWrite(8, LEFT_state);
  digitalWrite(7, LEFT_state);
  digitalWrite(6, RIGHT_state);
  digitalWrite(5, RIGHT_state);
  if ((long)(millis() - waitUntilSwitch) >= 0) {
    LEFT_state = LOW;
    RIGHT_state = LOW;
    whichLED = !whichLED;
    waitUntilSwitch += switchDelay;
  }
  if ((long)(millis() - strobeWait) >= 0) {
    if (whichLED == LEFTside)
      LEFT_state = !LEFT_state;
    if (whichLED == RIGHTside)
      RIGHT_state = !RIGHT_state;
    strobeWait += strobeDelay;
  }
}

void outboard() {
  for (int i = 0; i <= 7; i++) {
    digitalWrite(LEDright[i], LOW);
  }
  long time = millis() - sequenceStartTime;
  if (time < 300)
  {
    digitalWrite(12, HIGH);
    digitalWrite(11, HIGH);
    digitalWrite(10, LOW);
    digitalWrite(9, LOW);
    digitalWrite(8, LOW);
    digitalWrite(7, LOW);
    digitalWrite(6, LOW);
    digitalWrite(5, LOW);
  }
  else if (time < 600)
  {
    digitalWrite(12, LOW);
    digitalWrite(11, LOW);
    digitalWrite(10, LOW);
    digitalWrite(9, LOW);
    digitalWrite(8, LOW);
    digitalWrite(7, LOW);
    digitalWrite(6, HIGH);
    digitalWrite(5, HIGH);
  }
  else sequenceStartTime = millis();
}

void outboard_flash() {
  for (int i = 0; i <= 7; i++) {
    digitalWrite(LEDright[i], LOW);
  }
  digitalWrite(12, RIGHT_state);
  digitalWrite(11, RIGHT_state);
  digitalWrite(6, LEFT_state);
  digitalWrite(5, LEFT_state);
  if ((long)(millis() - waitUntilSwitch) >= 0) {
    LEFT_state = LOW;
    RIGHT_state = LOW;
    whichLED = !whichLED;
    waitUntilSwitch += switchDelay;
  }
  if ((long)(millis() - strobeWait) >= 0) {
    if (whichLED == LEFTside)
      LEFT_state = !LEFT_state;
    if (whichLED == RIGHTside)
      RIGHT_state = !RIGHT_state;
    strobeWait += strobeDelay;
  }
}

void inboard_6() {
  for (int i = 0; i <= 7; i++) {
    digitalWrite(LEDright[i], LOW);
  }
  long time = millis() - sequenceStartTime;
  if (time < 200)
  {
    digitalWrite(11, HIGH);
    digitalWrite(10, HIGH);
    digitalWrite(9, LOW);
    digitalWrite(8, LOW);
    digitalWrite(7, HIGH);
    digitalWrite(6, HIGH);
  }
  else if (time < 400)
  {
    digitalWrite(11, LOW);
    digitalWrite(10, LOW);
    digitalWrite(9, HIGH);
    digitalWrite(8, HIGH);
    digitalWrite(7, LOW);
    digitalWrite(6, LOW);
  }
  else sequenceStartTime = millis();
}

void inboard_6_flash() {
  for (int i = 0; i <= 7; i++) {
    digitalWrite(LEDright[i], LOW);
  }
  digitalWrite(11, LEFT_state);
  digitalWrite(10, LEFT_state);
  digitalWrite(9, RIGHT_state);
  digitalWrite(8, RIGHT_state);
  digitalWrite(7, LEFT_state);
  digitalWrite(6, LEFT_state);
  if ((long)(millis() - waitUntilSwitch) >= 0) {
    LEFT_state = LOW;
    RIGHT_state = LOW;
    whichLED = !whichLED;
    waitUntilSwitch += switchDelay;
  }
  if ((long)(millis() - strobeWait) >= 0) {
    if (whichLED == LEFTside)
      LEFT_state = !LEFT_state;
    if (whichLED == RIGHTside)
      RIGHT_state = !RIGHT_state;
    strobeWait += strobeDelay;
  }
}

void solid() {
  for (int i = 0; i <= 7; i++) {
    digitalWrite(LEDright[i], LOW);
  }
  long time = millis() - sequenceStartTime;
  if (time < 800)
  {
    digitalWrite(12, HIGH);
    digitalWrite(11, HIGH);
    digitalWrite(10, HIGH);
    digitalWrite(9, HIGH);
    digitalWrite(8, HIGH);
    digitalWrite(7, HIGH);
    digitalWrite(6, HIGH);
    digitalWrite(5, HIGH);
  }
  else if (time < 1600)
  {
    digitalWrite(12, LOW);
    digitalWrite(11, LOW);
    digitalWrite(10, LOW);
    digitalWrite(9, LOW);
    digitalWrite(8, LOW);
    digitalWrite(7, LOW);
    digitalWrite(6, LOW);
    digitalWrite(5, LOW);
  }
  else sequenceStartTime = millis();
}

void solid_flash() {
  for (int i = 0; i <= 7; i++) {
    digitalWrite(LEDright[i], LOW);
  }
  long time = millis() - sequenceStartTime;
  if (time < 200)
  {
    digitalWrite(12, HIGH);
    digitalWrite(11, HIGH);
    digitalWrite(10, HIGH);
    digitalWrite(9, HIGH);
    digitalWrite(8, HIGH);
    digitalWrite(7, HIGH);
    digitalWrite(6, HIGH);
    digitalWrite(5, HIGH);
  }
  else if (time < 400)
  {
    digitalWrite(12, LOW);
    digitalWrite(11, LOW);
    digitalWrite(10, LOW);
    digitalWrite(9, LOW);
    digitalWrite(8, LOW);
    digitalWrite(7, LOW);
    digitalWrite(6, LOW);
    digitalWrite(5, LOW);
  }
  else sequenceStartTime = millis();
}

void solid_flash_pause() {
  for (int i = 0; i <= 7; i++) {
    digitalWrite(LEDright[i], LOW);
  }
  digitalWrite(12, LEFT_state);
  digitalWrite(11, LEFT_state);
  digitalWrite(10, LEFT_state);
  digitalWrite(9, LEFT_state);
  digitalWrite(8, LEFT_state);
  digitalWrite(7, LEFT_state);
  digitalWrite(6, LEFT_state);
  digitalWrite(5, LEFT_state);
  if ((long)(millis() - waitUntilSwitch) >= 0) {
    LEFT_state = LOW;
    RIGHT_state = LOW;
    whichLED = !whichLED;
    waitUntilSwitch += switchDelay3;
  }
  if ((long)(millis() - strobeWait) >= 0) {
    if (whichLED == LEFTside)
      LEFT_state = !LEFT_state;
    if (whichLED == RIGHTside)
      RIGHT_state = !RIGHT_state;
    strobeWait += strobeDelay;
  }
}

void left_arrow() {
  unsigned long currenttimer = millis();
  if (currenttimer - lasttimer >= timer) {
    lasttimer = currenttimer;
    for (int i = 0; i <= 7; i++) {
    }
    light = light + counter;
    if (light > 7) {
      arrow_state = !arrow_state;
      light = 0;
      counter = 1;
    }
    if (arrow_state == HIGH) {
      digitalWrite(LEDleft[light], HIGH);
    }
    else if (arrow_state == LOW) {
      digitalWrite(LEDleft[light], LOW);
    }
  }
}

void right_arrow() {
  unsigned long currenttimer = millis();
  if (currenttimer - lasttimer >= timer) {
    lasttimer = currenttimer;
    for (int i = 0; i <= 7; i++) {
    }
    light = light + counter;
    if (light > 7) {
      arrow_state = !arrow_state;
      light = 0;
      counter = 1;
    }
    if (arrow_state == HIGH) {
      digitalWrite(LEDright[light], HIGH);
    }
    else if (arrow_state == LOW) {
      digitalWrite(LEDright[light], LOW);
    }
  }
}

void center_arrow() {
  unsigned long currenttimer = millis();
  if (currenttimer - lasttimer >= timer2) {
    lasttimer = currenttimer;
    for (int i = 0; i <= 7; i++) {
    }
    light = light + counter;
    if (light > 3) {
      arrow_state = !arrow_state;
      light = 0;
      counter = 1;
    }
    if (arrow_state == HIGH) {
      digitalWrite(centerright[light], HIGH);
      digitalWrite(centerleft[light], HIGH);
    }
    if (arrow_state == LOW) {
      digitalWrite(centerright[light], LOW);
      digitalWrite(centerleft[light], LOW);
    }
  }
}

void multi_pattern(){
  long time = millis() - sequenceStartTime2;
  if (time < 4000)
  {
    half_half_flash();
  }
  else if (time < 8000)
  {
    outboard();
  }
  else if (time < 12000)
  {
    two_by_two_parallel_flash();
  }
  else if (time < 16000)
  {
    solid_flash_pause();
  }
  else if (time < 20000)
  {
    outboard_flash();
  }
  else if (time < 24000)
  {
    tow_by_two_flash();
  }
  else if (time < 28000)
  {
    half_half();
  }
  else if (time < 32000)
  {
    two_by_two_parallel();
  }
  else sequenceStartTime2 = millis();
}