/*
  Arduino | coding-help
  nana — 12/8/24 at 1:02 PM
  Okay this matrix effect is functioning.
  I've got the encoders to simply pulse when pushed,
  and run the cylon effect left or right when the encoder
  is turned. different colour assigned to each encoder for
  easy troubleshooting.
*/

#include <FastLED.h>
#include <Encoder.h>

///////////////////////
// LED CONFIGURATION //
///////////////////////

#define NUM_LEDS_STRIP_1 69  // Number of LEDs on pin 5
#define NUM_LEDS_STRIP_2 22  // Number of LEDs on pin 6
#define TOTAL_LEDS (NUM_LEDS_STRIP_1 + NUM_LEDS_STRIP_2)

#define LED_PIN_1 5          // Data pin for strip 1
#define LED_PIN_2 6          // Data pin for strip 2
#define NUM_ROWS 11          // Total number of rows in the hexagonal grid
#define MAX_COLS 11          // Maximum columns in a row

CRGB leds[TOTAL_LEDS];       // LED array for both strips

// Logical-to-physical mapping
int mapping[NUM_ROWS][MAX_COLS] = {
  {65, 66, 67, 68, 69 + 11, 69 + 10, -1, -1, -1, -1, -1},   // Row 1
  {64, 63, 62, 61, 60, 69 + 12, 69 + 9, -1, -1, -1, -1},    // Row 2
  {54, 55, 56, 57, 58, 59, 69 + 13, 69 + 8, -1, -1, -1},    // Row 3
  {53, 52, 51, 50, 49, 48, 47, 69 + 14, 69 + 7, -1, -1},    // Row 4
  {39, 40, 41, 42, 43, 44, 45, 46, 69 + 15, 69 + 6, -1},    // Row 5
  {38, 37, 36, 35, 34, 33, 32, 31, 30, 69 + 16, 69 + 5},    // Row 6
  {22, 23, 24, 25, 26, 27, 28, 29, 69 + 17, 69 + 4, -1},    // Row 7
  {21, 20, 19, 18, 17, 16, 15, 69 + 18, 69 + 3, -1, -1},    // Row 8
  {9, 10, 11, 12, 13, 14, 69 + 19, 69 + 2, -1, -1, -1},     // Row 9
  {8, 7, 6, 5, 4, 69 + 20, 69 + 1, -1, -1, -1},             // Row 10
  {0, 1, 2, 3, 69 + 21, 69 + 0, -1, -1, -1, -1, -1}         // Row 11
};

// Encoder pin definitions
#define TURN_SW 8
#define TURN_DT 9
#define TURN_CLK 10

#define POWER_SW A5
#define POWER_DT A4
#define POWER_CLK A3

#define RESOLVE_SW A2
#define RESOLVE_DT A1
#define RESOLVE_CLK A0

#define HARVEST_SW 11
#define HARVEST_DT 12
#define HARVEST_CLK 13

Encoder turnEncoder(TURN_CLK, TURN_DT);
Encoder powerEncoder(POWER_CLK, POWER_DT);
Encoder resolveEncoder(RESOLVE_CLK, RESOLVE_DT);
Encoder harvestEncoder(HARVEST_CLK, HARVEST_DT);

// State variables for encoders
long lastTurnPos = 0;
long lastPowerPos = 0;
long lastResolvePos = 0;
long lastHarvestPos = 0;

// Helper function to set LED color by logical (row, column)
void setLEDColor(int row, int col, CRGB color) {
  if (row < 0 || row >= NUM_ROWS || col < 0 || col >= MAX_COLS || mapping[row][col] == -1) {
    return; // Out of bounds or invalid LED
  }
  leds[mapping[row][col]] = color;
}

// Function to pulse LEDs with a specified color
void pulseAllLEDs(CRGB color) {
  for (int row = 0; row < NUM_ROWS; row++) {
    for (int col = 0; col < MAX_COLS; col++) {
      setLEDColor(row, col, color);
    }
  }
  FastLED.show();
  delay(500); // Duration of pulse
  // Turn off LEDs
  for (int row = 0; row < NUM_ROWS; row++) {
    for (int col = 0; col < MAX_COLS; col++) {
      setLEDColor(row, col, CRGB::Black);
    }
  }
  FastLED.show();
}

void setup() {
  // Add LED strips to FastLED
  FastLED.addLeds<WS2812B, LED_PIN_1, GRB>(leds, 0, NUM_LEDS_STRIP_1);
  FastLED.addLeds<WS2812B, LED_PIN_2, GRB>(leds, NUM_LEDS_STRIP_1, NUM_LEDS_STRIP_2);

  FastLED.setBrightness(100); // Set brightness (0-255)

  // Set encoder switch pins as input
  pinMode(TURN_SW, INPUT_PULLUP);
  pinMode(POWER_SW, INPUT_PULLUP);
  pinMode(RESOLVE_SW, INPUT_PULLUP);
  pinMode(HARVEST_SW, INPUT_PULLUP);
}

void loop() {
  long turnPos = turnEncoder.read();
  long powerPos = powerEncoder.read();
  long resolvePos = resolveEncoder.read();
  long harvestPos = harvestEncoder.read();

  // Check if encoders are pressed and pulse corresponding colors
  if (digitalRead(TURN_SW) == LOW) {
    pulseAllLEDs(CRGB::Red);
  }
  if (digitalRead(POWER_SW) == LOW) {

    pulseAllLEDs(CRGB::Yellow);
  }
  if (digitalRead(RESOLVE_SW) == LOW) {
    pulseAllLEDs(CRGB::Green);
  }
  if (digitalRead(HARVEST_SW) == LOW) {
    pulseAllLEDs(CRGB::Blue);
  }

  // Check encoders for rotation and update effects
  if (turnPos != lastTurnPos) {
    lastTurnPos = turnPos;
    cylonEffect(CRGB::Red);
  }
  if (powerPos != lastPowerPos) {
    lastPowerPos = powerPos;
    cylonEffect(CRGB::Yellow);
  }
  if (resolvePos != lastResolvePos) {
    lastResolvePos = resolvePos;
    cylonEffect(CRGB::Green);
  }
  if (harvestPos != lastHarvestPos) {
    lastHarvestPos = harvestPos;
    cylonEffect(CRGB::Blue);
  }
}

// Cylon effect function modified to accept color parameter
void cylonEffect(CRGB color) {
  static int position = 0;    // Current position of the "head"
  static int direction = 1;   // Direction of the head (1 = forward, -1 = backward)

  // Clear all LEDs
  for (int row = 0; row < NUM_ROWS; row++) {
    for (int col = 0; col < MAX_COLS; col++) {
      setLEDColor(row, col, CRGB::Black);
    }
  }

  // Set the current position to the specified color
  for (int row = 0; row < NUM_ROWS; row++) {
    if (position < MAX_COLS && mapping[row][position] != -1) {
      setLEDColor(row, position, color);
    }
  }

  FastLED.show();

  // Update position
  position += direction;

  // Reverse direction at the ends
  if (position == MAX_COLS - 1 || position == 0) {
    direction = -direction;
  }

  delay(100); // Adjust speed of the effect
}
Turn
Power
Resolve
Harvest