#include <avr/pgmspace.h>  // Needed to store stuff in Flash using PROGMEM
#include "FastLED.h"       // Fastled library to control the LEDs

// How many leds are connected?
#define NUM_Row 16
#define NUM_Col 16
#define NUM_LEDS NUM_Row * NUM_Col

// Define the Data Pin
#define DATA_PIN 3  // Connected to the data pin of the first LED strip

// Define the array of leds
CRGB leds[NUM_LEDS];

const long ledarray0[] PROGMEM = {
				0x0000FFFF, 0x0000FFFF, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x000000FF, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 0x00FF0000, 
				0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000000FF, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000FF00, 
				0x0000FF00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000000FF, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
				0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000000FF, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000FF00, 
				0x0000FF00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000000FF, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
				0x00FFFF00, 0x00FFFF00, 0x00FFFF00, 0x00FFFF00, 0x00FFFF00, 0x00FFFF00, 0x00FFFF00, 0x00FFFF00, 0x00FFFF00, 0x00FFFF00, 0x000000FF, 0x00FFFF00, 0x00FFFF00, 0x00FFFF00, 0x00FFFF00, 0x0000FF00, 
				0x0000FF00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000000FF, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
				0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000000FF, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000FF00, 
				0x0000FF00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000000FF, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
				0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000000FF, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000FF00, 
				0x0000FF00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000000FF, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
				0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000000FF, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000FF00, 
				0x0000FF00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000000FF, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
				0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000000FF, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000FF00, 
				0x0000FF00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000000FF, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
				0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000000FF, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000FF00, 
};

void ReadArray(long Led_Array[]){
	for(int i = 0; i < NUM_LEDS; i++)
  {
    leds[i] = pgm_read_dword(&(Led_Array[i]));
  }
}

void Move_Col(bool Dir, int Times, int Speed){
  for(int k=0; k< Times; k++){
      for(int j=0; j< NUM_Row - 1; j++){
        for(int i=0; i< NUM_Col; i++){
          if(Dir==1){
            Move_Right_One();
          }
          else if(Dir== 0){
            Move_Left_One();
          }
          else{
            Move_Right_One();
          }
        }
      reverse_every_eight(NUM_LEDS);
      FastLED.show();
      delay(Speed);
    }
  }
}

void Move_Left_One(){
  CRGB temp = leds[0];
  for(int i = 0; i< NUM_LEDS; i++){
    leds[i]= leds[i+1];
  }
  leds[NUM_LEDS - 1] = temp;
}

void Move_Right_One(){
  CRGB temp = leds[NUM_LEDS-1];
  for(int i = NUM_LEDS; i>0 ; i--){
    leds[i]= leds[i-1];
  }
  leds[0] = temp;
}

void Move_Left_Test1(int Start,int End){
  CRGB temp = leds[Start];
  for(int i = Start; i< End; i++){
    leds[i]= leds[i+1];
  }
  leds[End - 1] = temp;
}
void Move_Left_Test2(int Start,int End){
  CRGB temp = leds[End-1];
  for(int i = End-1; i>Start ; i--){
    leds[i]= leds[i-1];
  }
  leds[Start] = temp;
}

void Move_UP(){
  for(int i=0;i<16;i++){
    Move_Left_Test1(0,16);
    Move_Left_Test1(32,48);
    Move_Left_Test2(16,32);
    Move_Left_Test2(48,64);
    FastLED.show();
    delay(200);
  }
}

void Move_Left_Test(){
  CRGB temp = leds[0];
  for(int i = 0; i< 16; i++){
    leds[i]= leds[i+1];
  }
  leds[NUM_Row - 1] = temp;
}
void Move_Right_Test(){
  CRGB temp = leds[NUM_Row-1];
  for(int i = NUM_Row; i>0 ; i--){
    leds[i]= leds[i-1];
  }
  leds[0] = temp;
}

void Move_UP_Test(){
  for(int i=0;i<256;i++){
    Move_Left_Test();
    }
    FastLED.show();
    delay(200);
  }

void reverse_array_portion(int Start, int End) {
  // Reverse the sub-array from 'start' (inclusive) to 'end' (exclusive)
  // While the start index is less than the end index
  while (Start < End) {
    // Swap elements at opposite ends of the sub-array
    CRGB temp = leds[Start];
    leds[Start] = leds[End - 1];
    leds[End - 1] = temp;

    // Move start and end indices towards each other
    Start++;
    End--;
  }
}

void reverse_every_eight(int size) {
  // size is the total size of the array (64)
  // Loop through the array in steps of 8 (number of elements to reverse)
  for (int i = 0; i < size; i += NUM_Col) {
    // Calculate the end index for the current sub-array (avoiding out-of-bounds)
    int End = (i + NUM_Col - 1 < size) ? i + NUM_Col -1  : size - 1;

    // Reverse the sub-array from 'i' (inclusive) to 'end' (inclusive)
    reverse_array_portion( i, End + 1);
  }
}

void setup() { 
FastLED.addLeds<NEOPIXEL,DATA_PIN>(leds, NUM_LEDS);  // Init of the Fastled library
FastLED.setBrightness(255);
}

void loop() {
  FastLED.clear();
  ReadArray(ledarray0);
  /*
  leds[0]=CRGB::Red;
  leds[8]=CRGB::White;
  leds[15]=CRGB::Yellow;
  leds[31]=CRGB::Red;
  leds[23]=CRGB::White;
  leds[16]=CRGB::Yellow;
  */
  FastLED.show();
  delay(500);
 // Move_Col(1,10,100);
 // Move_Col(0,10,100);
  //Move_UP();
  Move_UP_Test();
  //Move_Left_Test2();
  //Move_Left_Test2();
  FastLED.show();
  delay(500);
}