#include "HC595x2.h"
#include <Arduino.h> 

HC595x2::HC595x2(int latchPin, int clockPin, int dataPin) {
  this->latchPin = latchPin;
  this->clockPin = clockPin;
  this->dataPin = dataPin;
  this->msDelay = 0;
  this->currentStep = 0;

  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
}

void HC595x2::setDelay(int msDelay) {
  this->msDelay = msDelay;
}

void HC595x2::right() {
  run(15, 1);
}

void HC595x2::knightRider() {
  run(30,1);
}

void HC595x2::left() {
  run(15,-1);
}

void HC595x2::on() {
  setValue(255,255);
}

void HC595x2::off() {
  setValue(0,0);
}

void HC595x2::blink() {
  if (shouldRun()) {
    if (currentState) {
      on();
    } else {
      off();
    }
    currentState = !currentState;
    lastExecuted = millis();
  }
  
}

bool HC595x2::shouldRun() {
  return millis() - lastExecuted > msDelay;
}

void HC595x2::finishRun(int parts, int direction) {
  currentStep+=direction;
  if (currentStep > parts - 1) {
    currentStep = 0;
  }
  if (currentStep < 0) {
    currentStep = parts -1;
  }
  lastExecuted = millis();
}

void HC595x2::run(int parts, int direction) {
  if (shouldRun()) {
    setValue(LED2[currentStep], LED1[currentStep]);
    finishRun(parts, direction);
  }
}

void HC595x2::setValue(byte led1, byte led2) {
    digitalWrite(latchPin, LOW);
    shiftOut(led2);
    shiftOut(led1);
    // Set latchPin to high to lock and send data
    digitalWrite(latchPin, HIGH);
}

void HC595x2::shiftOut(byte dataOut) {
  // Shift out 8 bits LSB first,
  // on rising edge of clock
  boolean pinState;
  //clear shift register ready for sending data
  digitalWrite(dataPin, LOW);
  digitalWrite(clockPin, LOW);
  // for each bit in dataOut send out a bit
  for (int i=0; i<=7; i++) 
  {
    //set clockPin to LOW prior to sending bit
    digitalWrite(clockPin, LOW);
    // if the value of DataOut and (logical AND) a bitmask
    // are true, set pinState to 1 (HIGH)
    if ( dataOut & (1<<i)) {
        pinState = HIGH;
    } else {
        pinState = LOW;
    }
    //sets dataPin to HIGH or LOW depending on pinState
    digitalWrite(dataPin, pinState);
    //send bit out on rising edge of clock
    digitalWrite(clockPin, HIGH);
  }

  //stop shifting out data
  digitalWrite(clockPin, LOW);
}