//
#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
  }
}