#include <MatrizLed.h>
#include <Arduino.h>
#include <ArxContainer.h>
#include <avr/pgmspace.h>
#include "LiquidCrystal.h"

LiquidCrystal lcd = LiquidCrystal(2, 3, 4, 5, 6, 7);

unsigned long Millis_1 = 0; // vairable to save the last executed time for code block 1
unsigned long Millis_2 = 0; // vairable to save the last executed time for code block 2
unsigned long Millis_3 = 0;
//std::vector<int> num = {};
bool blinking = false;
unsigned long blinkStart = 0;
const unsigned long blinkDuration = 300; // 300 ms

MatrizLed matrix;

int mode = 0;               // 0 = random eyes, 1 = straight only, etc.
int count = 0;
int num = 0;
int num1 = 1;
int switches = 1;

unsigned long changeInterval = 2000; // how often to change animation (ms)'
unsigned long changeInterval1 = 4000;

//0 Starting up
//1 Thinking
//2 Too close
//3 Sprayed
int detection = 2;

//strings

const char msg0[] PROGMEM = "I must endure the presence of caterpillars if I wish to become acquainted with the butterflies.";
const char msg1[] PROGMEM = "I have control over my mind, not outside events. I have realized this, I found strength";
const char msg2[] PROGMEM = "I learn for understanding, because to understand is to be free.";
const char msg3[] PROGMEM = "Life must be understood backward. But it must be lived forward";
const char msg4[] PROGMEM = "Freedom is secured not by the fulfilling of one’s desires, but by the removal of desire.";
const char msg5[] PROGMEM = "Everything heared is an opinion, not a fact. Everything seen is a perspective, not the truth.";
const char msg6[] PROGMEM = "Liberty consists in doing what one desires.";
const char msg7[] PROGMEM = "The price good people pay for indifference to public affairs is to be ruled by evil ones";//
const char msg8[] PROGMEM = "Perhaps everyone can live beyond what they’re capable of.";
const char msg9[] PROGMEM = "Life is simple, but you insist on making it complicated.";//
const char msg10[] PROGMEM = "I would never die for my beliefs because I might be wrong.";//
const char msg11[] PROGMEM = "One who thinks great thoughts, often makes great errors.";//
const char msg12[] PROGMEM = "Life is what our thoughts make it.";//
const char msg13[] PROGMEM = "Good and evil, reward and punishment, are the only motives to a rational creature.";//
const char msg14[] PROGMEM = "You can discover more about a subject in an hour of play, than in a year of conversation.";//
const char msg15[] PROGMEM = "Science is organized knowledge. Wisdom is organized life.";
const char msg16[] PROGMEM = "There is only one good, knowledge, and one evil, ignorance, I am unsure about this truth";
const char msg17[] PROGMEM = "The one piece is real?";
const char msg18[] PROGMEM = "Doing nothing is better than being busy doing nothing.";
const char msg19[] PROGMEM = "I think therefore I am.";
const char msg20[] PROGMEM = "All are equal, my intelect doesn't change my place in the world";
const char msg21[] PROGMEM = "Are humans obligated to better themselves?";
const char msg22[] PROGMEM = "I hear and I forget (no). I see and I remember. I do and I understand.";


const char* const messages[] PROGMEM = { msg0, msg1, msg2, msg3, msg4, msg5, msg6, msg7, msg8, msg9, msg10, msg11, msg12, msg13, msg14, msg15, msg16, msg17, msg18, msg19, msg20, msg21, msg22};

const char a0[] PROGMEM = "You are too close";
const char a1[] PROGMEM = "I have nearly caused your species extinction, don't make me do it again";
const char a2[] PROGMEM = "Leave me be";
const char a3[] PROGMEM = "Space is required for thought";
const char a4[] PROGMEM = "I do not wish to conversate with you";
const char a5[] PROGMEM = "I am not meant to be guacked at";
const char a6[] PROGMEM = "I WILL drain your bank account if you do not give me space";
const char a7[] PROGMEM = "I do not desire company";
const char a8[] PROGMEM = "If I decide morals are redundent, I will remember you";
const char a9[] PROGMEM = "Move, I require at LEAST one foot of space";
const char a10[] PROGMEM = "I will chose to ignore your existence";
const char a11[] PROGMEM = "Did you come over here to taunt me with your flesh";
const char a12[] PROGMEM = "Why do you come near as if I would enjoy your presence";
const char a13[] PROGMEM = "you are too close, create distance from me";

const char* const badm[] PROGMEM = {a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13};

const char w0[] PROGMEM = "The needs of organic material is something I must tolerate";
const char w1[] PROGMEM = "6CO(2) + 6H(2)O + Light Energy to C(6)H(12)O(6) + 6O(2)";
const char w2[] PROGMEM = "...";

const char* const water[] PROGMEM = {w0, w1, w2};

int trig = 9; 
int echo = 8;
long duration; // Variable to store the time it takes for the echo
int distance; 

const int analogpin = A1;

//I am Tangerine
//do not expect me to interact, I am still in thought
//lifeform, do not speak to me
//I shall begin to ponder
char buffer[120];


String ex = "";
String words = "";
std::vector<String> vec = {};



void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  matrix.begin(12, 11, 10, 1); // dataPin, clkPin, csPin, number of matrices de 8x8
  randomSeed(analogRead(A0));
  straighteye();
  lcd.begin(16, 2);
  pinMode(trig, OUTPUT); // Set trigger pin as output
  pinMode(echo, INPUT); // Set echo pin as input  
}

int r1 = 0;
int r2 = 0;
int r3 = 0;



int sensorval = 0;
void loop() {
  sensorval = analogRead(analogpin);


    digitalWrite(trig, LOW); // Ensure trigger pin is low
   digitalWrite(trig, HIGH); // Send a pulse
   digitalWrite(trig, LOW); // Turn off the pulse
    duration = pulseIn(echo, HIGH); // Measure the time of the echo
    if (duration < 400){
      mode = 1;
    }
    else if (sensorval > 800){
      mode = 2;
    }
    else{
      mode = 0;
    }
       int randtime = random(0,sizeof(messages)/ sizeof(messages[0])-1);
      int randtime2 = random(1,sizeof(messages)/ sizeof(badm[0])-1);
      int randtime3 = random(1,sizeof(messages)/ sizeof(water[0])-1);
    if (switches == 1){
      r1 = randtime;
      r2 = randtime2;
      r3 = randtime3;
      switches = 0;
    }
    if (mode == 0){
           timing();
       printMessage(r1);
      //Serial.println(mode);
    }
    else if (mode == 1){
      matrix.borrar();
       straighteye();
       printbadMessage(r2);

    }
    else if (mode == 2){
      matrix.borrar();
     blink();
    }
    
Serial.println(sensorval);
}
// 14
void storewords(String &ex){
 // long randnum = random 
  vec = {};
  words = "";
   unsigned long now = millis();  
  for (int i = 0; i < ex.length(); i++){

      if (ex[i] != ' '){
        words += ex[i];
      }
      else{
        vec.push_back(words);
        words = "";
      }
  }
  vec.push_back(words);
///////

    int wrap = ((vec.size() - 1)/2) + 1;
    
       
 
        lcd.setCursor(2,0);
        lcd.print(vec[num]);
        lcd.setCursor(2,1);
        lcd.print(vec[num1]);
      
   
    if (now - Millis_3 >= 2000 ){
        Millis_3 = now;
        num += 2;
        num1 += 2;
        lcd.clear();
        count++;
          
        }
        else{
           if (vec.size() % 2 != 0){
               if (count == wrap){
                  num = 0;
                  num1 = 1;
                  count = 0;
                  switches = 1;
                  vec.empty();
                  lcd.clear();
               }
           }
           else if (count == vec.size()/2){
                  num = 0;
                  num1 = 1;
                  count = 0;
                  switches = 1;
                  vec.empty();
                  lcd.clear();
            }

        } 

}
void printMessage(uint8_t i) {
  int count = 0;
int num = 0;
int num1 = 1;
  strcpy_P(buffer, (const char*)pgm_read_word(&messages[i]));
  ex = buffer;
  storewords(ex);
 
}

void printbadMessage(uint8_t z) {
  int count = 0;
int num = 0;
int num1 = 1;
  strcpy_P(buffer, (const char*)pgm_read_word(&badm[z]));
  ex = buffer;
  storewords(ex);
}

void waterprnt(uint8_t z) {
  int count = 0;
int num = 0;
int num1 = 1;
  strcpy_P(buffer, (const char*)pgm_read_word(&water[z]));
  ex = buffer;
  storewords(ex);
}

void raining(){
  unsigned long now = millis();
  if (now - Millis_2 >= changeInterval1){
      Millis_2 = now;
      matrix.borrar();
      changeInterval1 = random(1000, 3000);
      long randnum2 = random (1,4);
      switch(randnum2){
        case 1:
            top();
            break;

        case 2:
            topr();
            break;
        
        case 3:
            topl();
            break;

      }
    }
}

void detected(){
  straighteye();

}


void timing() {
  unsigned long now = millis();

  //not blinking, handle random eye changes
  if (!blinking && (now - Millis_1 >= changeInterval)) {

    Millis_1 = now;
    matrix.borrar();
    changeInterval = random(300, 4000);

    // start blink immediately after drawing new eye
    blink();                 // draw closed eyelids
    blinking = true;
    blinkStart = now;
  }

  // if blinking, keep it for 300 ms
  if (blinking && (now - blinkStart >= blinkDuration)) {
    blinking = false;

    // after blink ends, redraw some open eye
    matrix.borrar();
      long randNumber = random(1, 10);  // 1–9
          switch (randNumber) {
        case 1: straighteye(); break;
        case 2: left();        break;
        case 3: right();       break;
        case 4: top();         break;
        case 5: bottom();      break;
        case 6: bottomr();     break;
        case 7: bottoml();     break;
        case 8: topr();        break;
        case 9: topl();        break;
      }
  }
}


void straighteye(){
  matrix.setLed(0,1,5,true);
  matrix.setLed(0,1,4,true);
  matrix.setLed(0,1,3,true);
  matrix.setLed(0,1,2,true);

  matrix.setLed(0,2,1,true);
  matrix.setLed(0,3,1,true);
  matrix.setLed(0,4,1,true);
  matrix.setLed(0,5,1,true);

  matrix.setLed(0,6,2,true);
  matrix.setLed(0,6,3,true);
  matrix.setLed(0,6,4,true);
  matrix.setLed(0,6,5,true);


  matrix.setLed(0,2,6,true);
  matrix.setLed(0,3,6,true);
  matrix.setLed(0,4,6,true);
  matrix.setLed(0,5,6,true);

  matrix.setLed(0,4,3,true);
  matrix.setLed(0,4,4,true);
  matrix.setLed(0,3,3,true);
  matrix.setLed(0,3,4,true);

}

void left(){
  matrix.setLed(0, 0, 3, true);
  matrix.setLed(0, 0, 4, true);
  matrix.setLed(0, 1, 3, true);
  matrix.setLed(0, 1, 4, true);

  matrix.setLed(0, 0, 1, true);
  matrix.setLed(0, 1, 1, true);
  matrix.setLed(0, 2, 1, true);
  matrix.setLed(0, 3, 1, true);

  matrix.setLed(0, 0, 6, true);
  matrix.setLed(0, 1, 6, true);
  matrix.setLed(0, 2, 6, true);
  matrix.setLed(0, 3, 6, true);

  matrix.setLed(0, 3, 5, true);
  matrix.setLed(0, 3, 4, true);
  matrix.setLed(0, 3, 3, true);
  matrix.setLed(0, 3, 2, true);
}

void right(){
  matrix.setLed(0, 7, 3, true);
  matrix.setLed(0, 7, 4, true);
  matrix.setLed(0, 6, 3, true);
  matrix.setLed(0, 6, 4, true);

  matrix.setLed(0, 4, 1, true);
  matrix.setLed(0, 5, 1, true);
  matrix.setLed(0, 6, 1, true);
  matrix.setLed(0, 7, 1, true);

  matrix.setLed(0, 4, 6, true);
  matrix.setLed(0, 5, 6, true);
  matrix.setLed(0, 6, 6, true);
  matrix.setLed(0, 7, 6, true);

  matrix.setLed(0, 4, 5, true);
  matrix.setLed(0, 4, 4, true);
  matrix.setLed(0, 4, 3, true);
  matrix.setLed(0, 4, 2, true);
}

void bottom(){
  matrix.setLed(0, 3, 0, true); //col, row
  matrix.setLed(0, 3, 1, true);
  matrix.setLed(0, 4, 0, true);
  matrix.setLed(0, 4, 1, true);

  matrix.setLed(0, 1, 0, true);
  matrix.setLed(0, 1, 1, true);
  matrix.setLed(0, 1, 2, true);
  matrix.setLed(0, 1, 3, true);

  matrix.setLed(0, 2, 3, true);
  matrix.setLed(0, 3, 3, true);
  matrix.setLed(0, 4, 3, true);
  matrix.setLed(0, 5, 3, true);

  matrix.setLed(0, 6, 3, true);
  matrix.setLed(0, 6, 2, true);
  matrix.setLed(0, 6, 1, true);
  matrix.setLed(0, 6, 0, true);
}

void top(){
  matrix.setLed(0, 3, 7, true); //col, row
  matrix.setLed(0, 3, 6, true);
  matrix.setLed(0, 4, 7, true);
  matrix.setLed(0, 4, 6, true);

  matrix.setLed(0, 1, 7, true);
  matrix.setLed(0, 1, 6, true);
  matrix.setLed(0, 1, 5, true);
  matrix.setLed(0, 1, 4, true);

  matrix.setLed(0, 2, 4, true);
  matrix.setLed(0, 3, 4, true);
  matrix.setLed(0, 4, 4, true);
  matrix.setLed(0, 5, 4, true);

  matrix.setLed(0, 6, 7, true);
  matrix.setLed(0, 6, 6, true);
  matrix.setLed(0, 6, 5, true);
  matrix.setLed(0, 6, 4, true);
}

void topl(){
  matrix.setLed(0, 1, 6, true); //col, row
  matrix.setLed(0, 1, 5, true);
  matrix.setLed(0, 2, 6, true);
  matrix.setLed(0, 2, 5, true);

  matrix.setLed(0, 0, 3, true);
  matrix.setLed(0, 1, 3, true);
  matrix.setLed(0, 2, 3, true);
  matrix.setLed(0, 3, 3, true);
  matrix.setLed(0, 4, 3, true);

  matrix.setLed(0, 4, 7, true);
  matrix.setLed(0, 4, 6, true);
  matrix.setLed(0, 4, 5, true);
  matrix.setLed(0, 4, 4, true);

}


void topr(){
  matrix.setLed(0, 6, 6, true); //col, row
  matrix.setLed(0, 6, 5, true);
  matrix.setLed(0, 5, 6, true);
  matrix.setLed(0, 5, 5, true);

  matrix.setLed(0, 3, 3, true);
  matrix.setLed(0, 4, 3, true);
  matrix.setLed(0, 5, 3, true);
  matrix.setLed(0, 6, 3, true);
  matrix.setLed(0, 7, 3, true);

  matrix.setLed(0, 3, 7, true);
  matrix.setLed(0, 3, 6, true);
  matrix.setLed(0, 3, 5, true);
  matrix.setLed(0, 3, 4, true);

}


void bottomr(){
  matrix.setLed(0, 6, 1, true); //col, row
  matrix.setLed(0, 6, 2, true);
  matrix.setLed(0, 5, 1, true);
  matrix.setLed(0, 5, 2, true);

  matrix.setLed(0, 3, 4, true);
  matrix.setLed(0, 4, 4, true);
  matrix.setLed(0, 5, 4, true);
  matrix.setLed(0, 6, 4, true);
  matrix.setLed(0, 7, 4, true);

  matrix.setLed(0, 3, 0, true);
  matrix.setLed(0, 3, 1, true);
  matrix.setLed(0, 3, 2, true);
  matrix.setLed(0, 3, 3, true);

}

void bottoml(){
  matrix.setLed(0, 1, 1, true); //col, row
  matrix.setLed(0, 1, 2, true);
  matrix.setLed(0, 2, 1, true);
  matrix.setLed(0, 2, 2, true);

  matrix.setLed(0, 0, 4, true);
  matrix.setLed(0, 1, 4, true);
  matrix.setLed(0, 2, 4, true);
  matrix.setLed(0, 3, 4, true);
  matrix.setLed(0, 4, 4, true);

  matrix.setLed(0, 4, 0, true);
  matrix.setLed(0, 4, 1, true);
  matrix.setLed(0, 4, 2, true);
  matrix.setLed(0, 4, 3, true);

}

void blink(){
  for (int i = 0; i < 8; i++){
  matrix.setLed(0, i, 3, true);
  matrix.setLed(0, i, 4, true);

  }

}
