/* 
 Adapted from sutaburosu's AA_lines.ino code. Many thanks!
*/

#include <FastLED.h>

#define WIDTH 64
#define HEIGHT 13
#define CANVAS_HEIGHT 64
#define RASTER_SPACING 5
#define NUM_LEDS (WIDTH * HEIGHT)

// CRGB bigCanvas[CANVAS_NUMLEDS + 1];
CRGB leds[NUM_LEDS + 1];

CRGBPalette16 rainbowPalette = {
  0xFF0000, 0x7F0000, 0xAB5500, 0x552A00, 0xABAB00, 0x555500, 0x00FF00, 0x007F00,
  0x00AB55, 0x00552A, 0x0000FF, 0x00007F, 0x5500AB, 0x2A0055, 0xAB0055, 0x55002A
};

CRGBPalette16 greenStripe = {
  0x00FF00, 0x00FF00, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000,
  0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000
};

CRGBPalette16 yellowStripe = {
  0xFFFF00, 0xFFFF00, 0xFFFF00, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000,
  0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000
};

CRGBPalette16 fadeFactorPalette = {
  0xFF0000, 0xFF0000, 0xFF0000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000,
  0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000
};


CRGBPalette16 redStripe = {
  0xFF0000, 0xFF0000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000,
  0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000
};

boolean _twist = false;

void setup() 
{
  FastLED.addLeds<NEOPIXEL, 3>(leds, NUM_LEDS);
  Serial.begin(9600);
  Serial.print(sizeof(CRGB));
}

#define STEPS       1

void loop()
{
    
    // fill_solid (struct CRGB *leds, int numToFill, const struct CRGB &color)
    // fill_gradient (T *targetArray, uint16_t numLeds, const CHSV &c1, const CHSV &c2, const CHSV &c3, const CHSV &c4, TGradientDirectionCode directionCode=SHORTEST_HUES)

  // static uint8_t colorIndex = 0 ;
  // for ( uint8_t i = 0; i < NUM_LEDS; i++) {
  //   leds[i] = ColorFromPalette( rainbowPalette, colorIndex, 255, LINEARBLEND );
  //   colorIndex += STEPS;
  // }

  rotateOne();
  // rotateTwo();

  // flashArm(random8(HEIGHT));
  // Serial.println(triwave8(beatsin8(120)));
}

void flashArm(int arm, int interval, int flashTime) {

  static int on = false;
  int onTime = flashTime;
  int offTime = interval - onTime;
  static long lastMillis = millis();
  if( millis() - lastMillis > offTime && !on ) {
      lastMillis = millis();
      fill_solid(leds + (arm*WIDTH), WIDTH, CHSV(255,255,255));
      FastLED.show();
      on = true;      
      // Serial.print("on: ");
      // Serial.println(onTime);
  }
  if( millis() - lastMillis > onTime && on ) {
    lastMillis = millis();
    FastLED.clear();
    FastLED.show();
    on = false;
    // Serial.print("off: ");
    // Serial.println(offTime);
  }
}

void rotateTwo() {
  static int arms[] = {0,4,8};
  static int hue = 0 ;
  #define NUM_ARMS (sizeof(arms) / sizeof(arms[0]))
  // #define PHASE_OFFSET floor(255/NUM_ARMS)

  FastLED.clear();
  // fill_solid(leds + (arms[0]*WIDTH), beatsin8(5,2,WIDTH), CHSV(hue,255,255));
  // fill_solid(leds + (arms[1]*WIDTH), beatsin8(5,2,WIDTH), CHSV(hue,255,255));

  for(int i = 0; i < NUM_ARMS; i++ ) {
    fill_solid(leds + (arms[i]*WIDTH), beatsin8(18,2,WIDTH), CHSV(hue,255,255));

    // fill_solid(leds + (arms[i]*WIDTH), WIDTH, CHSV(hue,255,255));

    arms[i]++;
    if( arms[i] == HEIGHT ) {
      arms[i] = 0;
    }
  }
  FastLED.show();
  hue++;
  delay(100);
}


void rotateOne() {
  static int arm = 0 ;
  static uint8_t hue = 0 ;
  // int bpm = 120;
  // int millisecs = 60000/bpm;
  
  int interval = 200;
  int flashTime = 20;
  // fill_solid(leds + (arm*WIDTH), WIDTH, CHSV(hue,255,255));
  // fill_solid(leds + (arm*WIDTH), beatsin8(12,2,WIDTH), CHSV(hue,255,255));
  flashArm(arm,interval,flashTime);

  EVERY_N_MILLISECONDS( interval ) { 
    arm++;
    if( arm == HEIGHT ) {
      arm = 0;
    }
  }
}

void fadeall(uint8_t fade_all_speed) {
  for (uint8_t i = 0; i < NUM_LEDS; i++) {
    leds[i].nscale8(fade_all_speed);
  }
}

uint16_t XY(uint8_t x, uint8_t y) {
  if (x >= WIDTH) return NUM_LEDS;
  if (y >= HEIGHT) return NUM_LEDS;
  return y * WIDTH + x;
}