//
#include <FastLED.h>
#define DEBUG
#define numLEDsInEachStrip 9
const byte potPins[] = {35,32,25,34};
const byte numPots = 4;
const byte lockPin = 33;
const int strip1 = 13;
const int strip2 = 12;
const int strip3 = 14;
const int strip4 = 27;
const int solution[numPots] = {5,2,9,7};
//Globals
int currentReadings[numPots] = {};
CRGB leds[numPots][numLEDsInEachStrip];
static uint16_t noiseOffset[3];
uint8_t noise[numPots][numLEDsInEachStrip];
enum PuzzleState {Initialising,Running,Solved};
PuzzleState puzzleState = Initialising;
bool checkIfPazzleSolved(){
  for(int i=0;i<numPots;i++){
    if(currentReadings[i] != solution[i]){
      return false;
    }
  }
  return true;
}
void onSolve() {
   #ifdef DEBUG
   Serial.println("Puzzle solved");
   #endif
  digitalWrite(lockPin,LOW);
  puzzleState = Solved;
}
void onUnsolved(){
  digitalWrite(lockPin,HIGH);
}
void setup() {
    #ifdef DEBUG
   Serial.begin(115200);
   #endif
  
for (int i =0; i<numPots; i++){
  pinMode(potPins[i],INPUT);
}
FastLED.addLeds<NEOPIXEL, strip1>(leds[0], numLEDsInEachStrip);
FastLED.addLeds<NEOPIXEL, strip2>(leds[1], numLEDsInEachStrip);
FastLED.addLeds<NEOPIXEL, strip3>(leds[2], numLEDsInEachStrip);
FastLED.addLeds<NEOPIXEL, strip4>(leds[3], numLEDsInEachStrip);
pinMode(lockPin,OUTPUT);
digitalWrite(lockPin,HIGH);
noiseOffset[0] = random16();
noiseOffset[1] = random16();
noiseOffset[2] = random16();
noiseOffset[3] = random16();
puzzleState = Running;
};
void fillnoise8(uint16_t speed, uint16_t scale) {
  for(int i=0; i< numPots; i++) {
    for(int j = 0; j< numLEDsInEachStrip; j++){
      noise[i][j] = inoise8(noiseOffset[0] + (i*scale), noiseOffset[1] + (j*scale), noiseOffset[2]);
    }
  }
  noiseOffset[2] +=speed;
}
long map2(long x, long in_min, long in_max,long out_min,long out_max){
  return (x - in_min)* (out_max - out_min+1) / (in_max - in_min+1) + out_min;
}
void getInput(){
  for(int i=0; i< numPots; i++) {
    int rawValue = analogRead(potPins[i]);
int scaledValue = map2(rawValue,0,4095,0,numLEDsInEachStrip);
scaledValue = constrain(scaledValue,0,numLEDsInEachStrip);
currentReadings[i] = scaledValue;
  #ifdef DEBUG
   Serial.print("Valve  ");
   Serial.print(i);
   Serial.print("Raw: ");
   Serial.print(rawValue);
   Serial.print("scaled:");
   Serial.println(scaledValue);
   #endif
  }
}
void setDisplay(int style = 0){
   fillnoise8(5,255);
   FastLED.clear();
   for(int i=0;i<numPots;i++){
        for (int x=0; x<currentReadings[i];x++){
           switch(style){
              case0:
              leds[i][x] = CHSV(noise[i][x],255,160);
              break;
              case 1:
              leds[i][x] = CHSV(150 +(int)(noise[i][x]>>2),255,
                constrain(16 + (2<<x) + (int)(noise[i][x]>>1),0,255));
                break;
                default:
                leds[i][x] = CRGB::CRGB::Yellow;
                break;
           }
        }
        if(currentReadings[i] >0){
          leds[i][currentReadings[i]-1] = CRGB(255,255,255);
        }
   }
   FastLED.show();
}
void loop() {
switch(puzzleState){
  case Initialising:
  puzzleState = Running;
  break;
  
  case Running:
  getInput();
  setDisplay(1);
  if(checkIfPazzleSolved()){
    onSolve();
  }
  break;
  case Solved:
  setDisplay(0);
  //abb more code to this lie when solved
  }
}