#include <avr/pgmspace.h>
#define MAX_TIME 255 * 4 // 4 microseconds * 255

// Define the LED pins
const int ledPins[] = {0,1,2,3,4,5};

//---------------------EFFECT ARRAYS START HERE---------------------//

//one led chasing//
const PROGMEM uint8_t a[][6] = 
{
  {0, 0, 0, 0, 0, 0},
  {255, 0, 0, 0, 0, 0},
  {0, 255, 0, 0, 0, 0},
  {0, 0, 255, 0, 0, 0},
  {0, 0, 0, 255, 0, 0},
  {0, 0, 0, 0, 255, 0},
  {0, 0, 0, 0, 0, 255},
  {0, 0, 0, 0, 0, 0}
};

//one led chasing inverted
const PROGMEM uint8_t b[][6] = 
{
  {255, 255, 255, 255, 255, 255},
  {0, 255, 255, 255, 255, 255},
  {255, 0, 255, 255, 255, 255},
  {255, 255, 0, 255, 255, 255},
  {255, 255, 255, 0, 255, 255},
  {255, 255, 255, 255, 0, 255},
  {255, 255, 255, 255, 255, 0},
  {255, 255, 255, 255, 255, 255}
};

//knight rider led chasing
const PROGMEM uint8_t c[][6] = 
{
  {255, 0, 0, 0, 0, 0},
  {0, 255, 0, 0, 0, 0},
  {0, 0, 255, 0, 0, 0},
  {0, 0, 0, 255, 0, 0},
  {0, 0, 0, 0, 255, 0},
  {0, 0, 0, 0, 0, 255},
  {0, 0, 0, 0, 255, 0},
  {0, 0, 0, 255, 0, 0},
  {0, 0, 255, 0, 0, 0},
  {0, 255, 0, 0, 0, 0}
};
//---------------------EFFECT ARRAYS END HERE---------------------//
void setup() 
{
  // Set the LED pins as output
  for (int i = 0; i < 6; i++) {
    pinMode(ledPins[i], OUTPUT);
  }
}


void loop() 
{
  cycleBrightness(a,8,6,150); 
  cycleBrightness(a,8,6,150); 
  cycleBrightness(a,8,6,150); 
  cycleBrightness(a,8,6,150); 
  cycleBrightnessRev(a,8,6,150); 
  cycleBrightnessRev(a,8,6,150); 
  cycleBrightnessRev(a,8,6,150); 
  cycleBrightnessRev(a,8,6,150); 

  cycleBrightness(b,8,6,150);
  cycleBrightness(b,8,6,150);
  cycleBrightness(b,8,6,150);
  cycleBrightness(b,8,6,150);
  cycleBrightnessRev(b,8,6,150);
  cycleBrightnessRev(b,8,6,150);
  cycleBrightnessRev(b,8,6,150);
  cycleBrightnessRev(b,8,6,150);
  
  cycleBrightness(c,10,6,150);
  cycleBrightness(c,10,6,150);
  cycleBrightness(c,10,6,150);
  cycleBrightness(c,10,6,150);
  cycleBrightness(c,10,6,150);
  cycleBrightness(c,10,6,150);
  cycleBrightness(c,10,6,150);
  cycleBrightness(c,10,6,150);
}


void cycleBrightness(const uint8_t brightnessLevels[][6], int rows, int cols, int dur) 
{
  // Loop through the brightness levels
  for (int i = 0; i < rows; i++) {
    // Set the brightness of each LED
    for (int j = 0; j < cols; j++) {
      softAnalogWrite(ledPins[j], pgm_read_byte(&brightnessLevels[i][j]));
    }
    // Wait for a second before changing the brightness
    delay(dur);
  }
}

void cycleBrightnessRev(const uint8_t brightnessLevels[][6], int rows, int cols, int dur) 
{
  // Loop through the brightness levels
  for (int i = rows - 1; i >= 0; i--) {
    // Set the brightness of each LED
    for (int j = 0; j < cols; j++) {
      softAnalogWrite(ledPins[j], pgm_read_byte(&brightnessLevels[i][j]));
    }
    // Wait for a second before changing the brightness
    delay(dur);
  }
}


void softAnalogWrite(int pin, int value) 
{
  static unsigned long lastUpdateTime = 0;
  static int i = 0;

  if (value == 0) {
    digitalWrite(pin, LOW);
  } else if (value == 255) {
    digitalWrite(pin, HIGH);
  } else {
    unsigned long currentTime = micros();
    if (currentTime - lastUpdateTime >= 4) { // 4 microseconds
      digitalWrite(pin, i < value);
      i = (i + 1) % MAX_TIME;
      lastUpdateTime = currentTime;
    }
  }
}