#include <Wire.h>
#include <LiquidCrystal_I2C.h> 
#include <LcdBarGraphX.h>
#include <FastLED.h>


// --- LEDS ---
#define LED_TYPE WS2811
#define COLOR_ORDER RGB
#define MASTER_BRIGHTNESS 200

#define DATA_PIN_A 11  // update pin numbers for data lines as needed
#define DATA_PIN_B 10
#define DATA_PIN_C 8
#define DATA_PIN_D 9

#define NUM_LEDS_A 22  // adjust number of pixels as needed
#define NUM_LEDS_B 12
#define NUM_LEDS_C 12
#define NUM_LEDS_D 22

CRGB ledsA[NUM_LEDS_A];
CRGB ledsB[NUM_LEDS_B];
CRGB ledsC[NUM_LEDS_C];
CRGB ledsD[NUM_LEDS_D];

static uint8_t hueA=123;



// --- Robot Functionality ---

// Initialize LCD
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); 

LcdBarGraphX bar(&lcd, 20, 0, 3); // -- Second line at column 0
 
// Define ports
int poti_port=A0;
int poti_value=0;
int amount=0;
int poti_last_value;
int poti_read;
int poti_new_value;

int button_port=12;
int button_pressed=0;

int relay_port=13;
bool relay_status=false;

bool pump_running=false;
char state='i';

int led_bottle = 1;
int led_pump = 2;
int led_glass= 3;

unsigned long previousMillis=0;
unsigned long currentMillis=0;

// 500ml/min mean 120ms per ml
int ms_per_ml=132;
int ml_pumped=0;

void setup()
{

  // --- Robot Functionality ---
  
  pinMode(button_port, INPUT);
  pinMode(relay_port, OUTPUT);

  //Initialize lcd
  lcd.begin(20,4);

  // Standard Set text
  lcd.setCursor ( 0, 0 );
  lcd.print("  * * Cockstar * *  ");  
  lcd.setCursor ( 0, 1 );        
  lcd.print("Starting...         ");   

  Serial.begin(9600);

  // --- LEDS ---
  delay(2500);  //power up delay
  FastLED.addLeds<LED_TYPE, DATA_PIN_A, COLOR_ORDER>(ledsA, NUM_LEDS_A);
  FastLED.addLeds<LED_TYPE, DATA_PIN_B, COLOR_ORDER>(ledsB, NUM_LEDS_B);
  FastLED.addLeds<LED_TYPE, DATA_PIN_C, COLOR_ORDER>(ledsC, NUM_LEDS_C);
  FastLED.addLeds<LED_TYPE, DATA_PIN_D, COLOR_ORDER>(ledsD, NUM_LEDS_D);
  FastLED.setBrightness(MASTER_BRIGHTNESS);
  FastLED.clear();
  
}
 
void loop()
{
 // --- Robot Functionality ---
  
 // Read status of poti
 poti_read =analogRead(A0);
 // 
 poti_new_value=map(poti_read,0,1023,0,101);
if(poti_value != poti_new_value && poti_last_value != poti_new_value) {
  poti_last_value=poti_value;
  poti_value=poti_new_value;
}

 
 // Read status of button
 int button_pressed=digitalRead(button_port);
Serial.println(button_pressed);

  // Reset title
  lcd.setCursor ( 0, 0 );
  lcd.print("  * * Cockstar * *  ");  

// States:
// i: idle
// w: waiting
// r: Running
// f: Finished

//    lcd.print("                    ");  

switch(state){
  case 'i':
    // Idle
    lcd.setCursor ( 0, 1 );
    lcd.print("Ready. Place glass. ");   
    pump_running=false;
    previousMillis=millis();

     // Print bar graph only if pump running
        if(poti_value>0){
        bar.drawValue(ml_pumped,poti_value);
      } else {
          lcd.print("                    ");   
      }
      
    if(button_pressed){
      state='w';
    }
  break;

  case 'w':
    // Waiting until glass is finally placed
    lcd.setCursor ( 0, 1 );
    lcd.print("Wait...             ");
    lcd.print("                    ");   

    if(!button_pressed){
      state='i';
    }

    // wait 500ms
    if(millis()-previousMillis>500) {
      state='r';
      previousMillis=millis();
    }
  break;

  case 'r':
    // Pump is running
    pump_running=true;

    if(!button_pressed){
      state='i';
    }

    // Run pump only when poti at least 1ml
    if(poti_value > 0){

      // If poti is over 100ml, run forever
      if(poti_value > 100) {
         lcd.setCursor ( 0, 1 );
         lcd.print("Pump running.       "); 
      } else {

        // Else, normal mode limited by poti_value
        lcd.setCursor ( 0, 1 );
        lcd.print("Filling glass.      ");  

        ml_pumped=int((millis()-previousMillis)/ms_per_ml);

        if(ml_pumped >= poti_value) {
          pump_running=false;
          state='f';
          previousMillis=millis();
        }

        lcd.setCursor ( 0, 3 );

     // Print bar graph only if pump running
        if(poti_value>0){
        bar.drawValue(ml_pumped,poti_value);
      } else {
          lcd.print("                    ");   
      }
      }
    } else {
      lcd.setCursor ( 0, 1 );
      lcd.print("Pump deactivated.   "); 
      pump_running=false;

    }
  break;

  case 'f':
    // Glass filled
    lcd.setCursor ( 0, 1 );
    lcd.print("Ready, remove glass.");      

    if(!button_pressed){
      state='i';
    }
  break;
}

// Update pump status
if(pump_running) {
  digitalWrite(relay_port, 1);
} else {
  digitalWrite(relay_port, 0);
}

// Update fluid amount
//lcd.setCursor ( 0, 2 );
//lcd.print("                    "); 
lcd.setCursor ( 0, 2 );

if(poti_value==0) {
    lcd.print("Amount: None        ");
} else {
  if(poti_value>100) {
    lcd.print("Amount: Infinite  ");
  } else {
    lcd.print(String("Amount: ") + poti_value + "ml     ");
  }
}


  // --- LEDS ---
 EVERY_N_MILLISECONDS(50) {
    //static uint8_t hueA;
    fill_solid(ledsA, NUM_LEDS_A, CHSV(hueA, 255, 255));
    hueA++;
  }



  //------code for the second strip, ledsB here------
  // Putting the ledsB pattern inside this EVERY_N section allows
  // the speed for just this strip to be individually adjusted.
  // This will run every 500 milliseconds.
  // Use ledsB in this section, such as ledsB[i], and NUM_LEDS_B
  // with for loops so it uses the correct length of strip B.
  // For example:

//  EVERY_N_MILLISECONDS(20) {

//  }



  //------code for ledsC pattern------
  // This strip can run a similar or different pattern, and have
  // it's own timing.  This will run every 35 milliseconds.
  // Use ledsC[i] and NUM_LEDS_C in this section.

  EVERY_N_MILLISECONDS(20) {
    static uint8_t hueC;
    static uint8_t brightnessC;
    static uint8_t countC;
    //fill_solid(ledsC, NUM_LEDS_B, CHSV(hueB, 255, 255));
    //hueB++;

  if(state=='f'){
    fill_solid(ledsC, NUM_LEDS_C, CHSV(255, 0, brightnessC));
    countC++;
if(countC==10){
    countC=0;
if(brightnessC<10){
  brightnessC=255;
  } else {
    brightnessC=0;
  }
}
} else {
    fill_solid(ledsC, NUM_LEDS_C, CHSV(hueC, 255, 255));
}
hueC++;
}



  //------code for ledsLogo pattern------
  // This strip can also do it's own individual thing.  
  // Use ledsD and NUM_LEDS_D in this section.

  EVERY_N_MILLISECONDS(20) {
    fill_rainbow( ledsD, NUM_LEDS_D, millis()/5, 12);
  }


  // Update the display for all strips.
  FastLED.show();

}
