#define PIN_CLOCK 10 
#define PIN_LATCH 9
#define PIN_DATA 11

#define ANIM_MIN_DUR 4000
#define ANIM_MAX_DUR 8000

#define DELAY 100 //main loop delay, reduce this to 50 ot 100

float accel_factor = 1;
uint16_t data=0;
uint8_t ring_data=0;
uint16_t step=0;
uint32_t anim_start_time;
uint16_t anim_duration = 5000;

void (*stepFuncPtr)();
uint8_t stepFuncArraySize;


void send_data(){  
  //combine ring_data and data
  data = (data & 0b0001111111111111) | (ring_data << 13);  
  
  Serial.println(ring_data,BIN);
  Serial.println(data,BIN);
  digitalWrite(PIN_LATCH,LOW);
  shiftOut(PIN_DATA, PIN_CLOCK, MSBFIRST, data >> 8);
  shiftOut(PIN_DATA, PIN_CLOCK, MSBFIRST, data);
  digitalWrite(PIN_LATCH,HIGH);
  delay(1);
  digitalWrite(PIN_LATCH,LOW);

}


void flash_step(){
  ring_data = 0b000;
  if (step == 0){
    data = 0;
  }
  data = data ^ 0b1111111111;
}


void radial_chase_step(){
   if(step % 10 == 0){
    data = 0b0101010101; //half leds on only for power reason
  }else{
    ring_data = ring_data << 1;
    if (ring_data > 4){
      ring_data = 0b110;
    }
  }
}

void chase_step(){
  ring_data = 0b110;
  if(step % 10 == 0){
    data = 1;
  }else{
    data = data << 1;    
  }
}

void rev_chase_step(){
  ring_data = 0b110;
  if(step % 10 == 0){
    data = 0b1000000000;
  }else{
    data = data >> 1;    
  }
}

void sym_chase_step(){
  ring_data = 0b110;
  if(step % 5 == 0){
    data = 0b0000100001;
  }else{
    data = data << 1;    
  }
}

void rev_sym_chase_step(){
  ring_data = 0b110;
  if(step % 5 == 0){
    data = 0b1000010000;
  }else{
    data = data >> 1;    
  }
}


void chase3_step(){
  ring_data = 0b000;
  if(step % 10 == 0){
    data = 0b1010101010;
  }else{
    uint16_t msb = data & 0b1000000000;
    data = data << 1;   
    data &= 0b0001111111111111; 
    if (msb){
      data |= 1;
    }
  }
}

void twinkle_step() {
    accel_factor = 1;
    ring_data = 0b000;
    data = 0;
    uint8_t max = random(5);
    for (int i = 0; i < max; i++) {      
      data |= (1 << random(10));
    }
}
  
//############################

void (*stepFuncArray[])() = { twinkle_step, chase_step, rev_chase_step, rev_sym_chase_step, sym_chase_step};
//void (*stepFuncArray[])() = { twinkle_step, chase3_step, chase_step, radial_chase_step };
//void (*stepFuncArray[])() = { rev_sym_chase_step };

void setup() {
  Serial.begin(115200);
  randomSeed(analogRead(A0));
  pinMode(PIN_CLOCK, OUTPUT);
  pinMode(PIN_LATCH, OUTPUT);
  pinMode(PIN_DATA, OUTPUT);

  ring_data = 0b110;
  data = 0b0001111111111111;

  stepFuncArraySize =  sizeof(stepFuncArray) / sizeof(stepFuncArray[0]);
  stepFuncPtr = stepFuncArray[0];
  anim_start_time = millis();
}

void loop() {
  if (millis() - anim_start_time > anim_duration){
    anim_duration = random(ANIM_MIN_DUR,ANIM_MAX_DUR);
    anim_start_time = millis();
    uint8_t fNumber = random(0,stepFuncArraySize);
    Serial.println(fNumber);
    Serial.println(anim_duration);
    stepFuncPtr = stepFuncArray[fNumber];
    step = 0;
    accel_factor=1;
  }
  stepFuncPtr();

  send_data();
  step ++;
  delay(DELAY/accel_factor);
}
