import processing.core.*; 
import processing.data.*; 
import processing.event.*; 
import processing.opengl.*; 

import processing.serial.*; 

import java.util.HashMap; 
import java.util.ArrayList; 
import java.io.File; 
import java.io.BufferedReader; 
import java.io.PrintWriter; 
import java.io.InputStream; 
import java.io.OutputStream; 
import java.io.IOException; 

public class guitayourt_processing extends PApplet {

// creation des variables boutons
Bouton boutonOkReglage, boutonRefaireReglage, boutonQuitter, boutonWeb;

PFont font20, font12,font15, font10, font25;

// après la connexion réussie les étapes : régagles / communication arduino / mesure de la durée
int etape=0; 

long  raz; // pour laisser la durée affiché 3000 ms puis remise à zero du temps

// pour changer l'icone de l'executable aller dans processing-3.5.4\modes\java\application
// et changer sketch.ico ! c'est tout !

public void setup(){
  
  //size(1024,768,P2D);
 
  // chargement d'une police sympa pour les boutons et autres -> présente dans le dossier data (à la racine)
  font20 = loadFont("Arial-BoldMT-20.vlw");
   font25 = loadFont("Arial-BoldMT-25.vlw");
   font15 = loadFont("Arial-BoldMT-15.vlw");
    font12 = loadFont("Arial-BoldMT-12.vlw");
  font10 = loadFont("Arial-BoldMT-10.vlw");
  
  // charger les images en mémoire
  chargerImages();
  
  // ************** Initialiation des BOUTONS - class Bouton **************
  // new bouton(x, y, largeur, hauteur, texte, fonction, style)
  boutonOkReglage =  new Bouton(750, 535, 60, 20, "Ok", "okReglageFonction",1);
  boutonRefaireReglage =  new Bouton(540, 50, 100, 20, "Refaire réglage", "refaireReglageFonction",1);
  boutonQuitter =  new Bouton(75, 150, 60, 25, "Quitter", "quitterFonction",1);
  boutonWeb =  new Bouton(75, height-13, 130, 25, "site", "webFonction",2);
  
   
  periode=0;
  
  connexionArduino();

}

public void draw(){
  background(50);
  
  // creation du fond 
  // barre verticale à gauche et l'image de la carte arduino  
  stroke(0); strokeWeight(1);
  fill(30);  rect(0, 0, 150, height);
  image(imageArduino, 20,20);
  
  // Nom du TP dans la barre à gauche
  fill(200,200,200);textFont(font20);
  text("        T.P.    \n Guitayourt", 10, height/2); 
  
 // afficher les FPS
    fill(80,80,80);textFont(font10);
    text(PApplet.parseInt(frameRate), 5, 10); 

  boutonQuitter.represente();

// copyright
  //  boutonWeb.represente(); le bouton n'est pas representé mais le lien fonctionne !
    fill(100,100,100);textFont(font10);
    text("Cyril Vallet (c) - 2020 \n www.sciencesmania.com", 5, height-18); 
    
  
  
  // *******************************************************
  // **********  gestion de la connexion à l'arduino********
  //********************************************************

  if (etatConnexionArduino == -1){
    pbConnexion();
  }
  
   if (etatConnexionArduino == 1){
    fill(255,255,255);  textFont(font10); 
    text("Connexion à l'arduino ...", 25, 105);
    maConnexionArduino.write("g");  // envoie g pour voir si l'arduino la recoit et renvoie g (g pour go ;-))) )
  }
  
   if (etatConnexionArduino== 2){
    // écrire connecté en vet ! en dessous l'image de la carte Arduino
    fill(0,255,150);textFont(font10); 
    text("Connecté", 25, 105); 
  
  } 
  
  
  // *******************************************************
  // **********  Connexion ok on passe au programme
  //********************************************************
  
  // la connexion est réussie on passe 
// d'abord au réglage puis aux mesures
  if (etatConnexionArduino== 2 && etape==0) {
    // l'arduino n'envoie encore rien comme données
    maConnexionArduino.write('r'); // ordre d'envoie la tension 
    etape =1;
  }
  
  // réglage de la position du fil par rappport à la del rouge
  if (etatConnexionArduino==2 && etape==1){
     reglage(); 
  
  }
  

  if (etatConnexionArduino==2 && etape==2){
     reglage(); 
    
  }  
  
  if (etatConnexionArduino== 2 && etape==4) {
    maConnexionArduino.write('n'); 
    etape=5;
  }
  
  if (etatConnexionArduino==2 && etape==5){
     mesure();
  }
  

}
PFont font;


class Bouton {
  
  int bx;
  int by;
  int bw;
  int bh;
  String btext;
  String bfonction;
  int bstyle;
  
  // La position du bouton est en mode CENTER !
  // x position du bouton horizontale , y verticale, w largeur totale, h hauteur totale, 
  // text : texte du bouton , fonction : la fonction associée
  // style pour l'apparence
  Bouton(int x,int y, int w, int h, String text, String fonction,  int style){
    bx=x;
    by=y;
    bw=w;
    bh=h;
    btext =text;
    bfonction = fonction;
    bstyle = style;
  }
  
  //void actualise(){
  //  bx++;
  //  if (bx>width) bx=0;
  //}
  
  public void represente(){
    rectMode(CENTER);
    
    if (mouseX > bx-bw/2 && mouseX < bx+bw/2 && mouseY > by-bh/2 && mouseY < by+bh/2){
      
      if (mousePressed) {
         stroke(255);fill(1,1,1); strokeWeight(1);
         rect(bx, by, bw,bh,5);
         noStroke();
        }
       else {
         stroke(255);fill(67,181,73); strokeWeight(1);
         rect(bx, by, bw,bh,5);
         noStroke();
       }
      // cursor(HAND);
    } else {
    
    
    if (bstyle == 1) { stroke(255);fill(116,116,116); strokeWeight(1);}
    if (bstyle == 2) { stroke(255);fill(150,50,50); strokeWeight(1);}
    rect(bx, by, bw,bh,5);
     noStroke();
     //cursor(ARROW);
   
    }
    
     rectMode(CORNER);
     
    fill(255,255,255); textFont(font12);textAlign(CENTER);
    text(btext, bx, by +12/2-2);
    textAlign(CORNER);
    
  }
  
  public String checkOver() {
    if (mouseX > bx-bw/2 && mouseX < bx+bw/2 && mouseY > by-bh/2 && mouseY < by+bh/2){
    // println(bx);
     return bfonction;
    } else {
     return "";
    }
  }
  
  
}

public void mouseReleased(){

  String quelleFonction ;
  
  quelleFonction = boutonOkReglage.checkOver();    
    if (quelleFonction.equals("okReglageFonction") && etape==1){
      maConnexionArduino.write('m');
      etape=3;
     // cursor(ARROW);
    }
    
   quelleFonction = boutonRefaireReglage.checkOver();
    if (quelleFonction.equals("refaireReglageFonction") && etape==5){
      etape=0;
     //  cursor(ARROW);
    }
    
    quelleFonction =  boutonWeb.checkOver();
    if (quelleFonction.equals("webFonction")){
      link("https://www.sciencesmania.com");
    }
    
  quelleFonction =  boutonQuitter.checkOver();
    if (quelleFonction.equals("quitterFonction")){
      exit();
    }

}
PImage imageArduino;
PImage imageCommentGratter;
PImage imageCourbe;
PImage imageCourbeZero;
PImage imageReglage;

public void chargerImages() 
{
 imageArduino = loadImage("arduinosmall.png");
 imageCommentGratter = loadImage("commentgratter.png");
 imageCourbe = loadImage("courbe2.png");
 imageCourbeZero = loadImage("courbezero.png");
 imageReglage = loadImage("reglage.png");
}
float periode;
float tableauMesure[] ={0,0,0,0,0,0,0,0,0,0}; 

public void mesure(){
  
   boutonRefaireReglage.represente();
  
   // cadre des photos
    strokeWeight(5);fill(0,0,0);
    rect(250, 250, 718, 272); 
    rect(670, 100, 300, 127); 
    strokeWeight(1);
    //pour atténuer la photo, ce n'est pas l'objet du T.P. mais une de faire.
    // il faut se concentrer sur la mesure ! 
    tint(150, 255);image(imageCommentGratter, 670, 100);tint(255, 255);
    
       // rendre atténué le texte REGLAGE pour montrer que cette étape est faite
    fill(0,100,100);ellipse(250,50, 50,50);
    fill(100,100,100); textFont(font25); text("1", 242, 58);
    textSize(25); text("Réglage acquis", 285, 58);

    
    // Afficher l'étape en grand : MESURE
    fill(0,200,200);ellipse(250,120, 50,50);

    fill(255,255,255); textFont(font25); text("2", 242, 128);
    textFont(font25); text("Mesures", 285, 128);

    
    // les conseils
    textFont(font12); 
      fill(200,200,200); 
      text("*   Bien maintenir le capteur avec votre index.\n\n*   Gratter le fil modérement entre le pot et le capteur. \n\n", 285, 160);
    
   
 
    
    fill(255,0,0);  textFont(font20);   
    if (periode == 0){  
      image(imageCourbeZero, 250, 250); // courbe plate pour donner l'impression qu'il n'y pas de mesures
      text("En attente...", 650, 280);
    } else {
      // montrer ce qu'aurait pu donner la coruabe
      image(imageCourbe, 250, 250); 
      // afficher la valeur de la tension
      text(nfc(periode,2) + " ms", 650, 280);
      
      
      // si la durée est trop grande, afficher que cette mesure ne sera pa retenue
      if (periode > 1000 && periode != 0) {
        fill(220,100,0); textFont(font15); 
        text("La valeur est vraiment trop grande \net ne sera pas retenue", 710, 310); 

      }

    
    }
    
 
    // au bout de 3 s que la durée est affichée sur la courbe
     if ((millis()-raz) > 3000 && periode != 0) {

       // remplir le tableau des mesures
      for (int i=0;i<10;i++){

        if (periode < 1000.0f){ // si duree > 1000 ms elle n'est pas retenue
          
          if (tableauMesure[i]==0   ){
            tableauMesure[i] = periode;
            break;
          } else {
             if (i==9 ) {      
            tableauMesure = subset(tableauMesure,1);     
             tableauMesure =append(tableauMesure, periode);
    
             }
          } 
        }
      }
      // remettre En attente une fois la valeur enregistrée
      periode = 0;

    } 
    

    
    fill(100,100,100); textFont(font10); 
    text("Cette courbe est une image \nmais elle provient de mesures réelles \neffectuées avec un oscillospe \net avec le même dispositif.", 285, 260);
  
    // cadre pour tableau de mesures
    fill(100); stroke(0);
    for (int i=0;i<11;i++){  
      rect(245 +i*65, 535, 65, 50);
    }

    // afficher tableau de mesures
    fill(255);    textFont(font12);
    text("Mesures  \n  (ms)  ", 255, 560);
    
   textFont(font15);
    for (int i=0;i<10;i++){  
      if (tableauMesure[i] == 0 ) {
        text("--", 330+i*65, 560);  
      } else {
        text(nfc(tableauMesure[i],2), 330+i*65, 560);      
      }    
    }
    
    // pour effacer les mauvaises mesures
    // on affiche la position du pointeur de la souris
    // avec un cadre rouge 
    for(int c=0; c<10;c++) {
      if (mouseX > 310 +c*65 && mouseX < 310+65 +c*65&& mouseY>535 && mouseY<535+50){
        fill(255,0,0);
        rect(310+c*65, 535+40, 65, 10);  
        
      } 
    }
    if (mouseX > 310  && mouseX < 960 && mouseY>535 && mouseY<535+50){

       cursor(HAND);
      }  else {

     cursor(ARROW);
    }
    
    // message pour signaler que l'on peut supprimer une valeur
    fill(100,100,100); textFont(font10); 
    text("En cliquant sur une mesure, vous pouvez la supprimer si vous la jugez erronée.", 312, 600);
 
  
}

public void mousePressed(){

  // reperer la position de la souris pour effacer les valeurs si on clique dans une case.
  if (etape==5) {
    for(int c=0; c<10;c++) {
        if (mouseX > 310 +c*65 && mouseX < 310+65 +c*65&& mouseY>535 && mouseY<535+50){
          
          if (tableauMesure[c]!=0){
            tableauMesure[c]=0;
          }
        }  
    }
  }
}
public void pbConnexion() { 

  fill(255, 80, 0);   textFont(font25);
  text("Problème de connexion \navec la carte Arduino !", 175, 50);

  fill(150, 150, 150);    textFont(font15);
  text("- Vérifier qu'il n'y a QUE la carte arduino de branchée sur l'ordinateur.\n\n- Fermer ce logiciel \n\n- Débrancher puis brancher à nouveau la carte Arduino.\n\n- Relancer ce logiciel.\n\n\n\n- Si le problème persiste, revoir précisement la procédure \ndans la partie fabrication du Guitayourt sur www.sciencesmania.com", 200, 150);
}
public void reglage(){
  // présentation avec texte et le rond avec le numéro
   fill(0,200,200);
   ellipse(250,50, 50,50);
   
 
   fill(255,255,255); textFont(font25); text("1", 242, 58);
   textSize(25); text("Réglage", 285, 58);
   
   
    fill(100,200,255); textFont(font12); 
    text("Il s'agit de positionner correctement le capteur par rapport au fil \nafin d'obtenir des signaux exploitables.\n", 285, 100);
    fill(200,200,200); 
    text("*   Maintenir le capteur avec votre index.\n\n*   Tourner la molette afin de positionner le fil à peu près au milieu de la del. \nLa tension doit être élevée.\n\n*   Agir de nouveau sur la molette doucement afin d'atteindre le seuil de tension nécessaire. \nLa tension doit baisser et le fil doit être décalé par rapport à la del rouge. ", 285, 145);
    
    
    fill(200,150,100); textFont(font12);
    text("Le capteur mesure une tension en fonction de la lumière reçue. \nUne luminosité ambiante très changeante peut perturber la mesure.", 285,600);
  
   stroke(0,0,0);
   strokeWeight(5);   rect(285,280,200,259);   strokeWeight(1); // pour encadrer l'image
   image(imageReglage,285,280); 
   //flèche du mot capteur sur l'image 
   stroke(200,200,200);
   line(320, 400, 320, 585); line(300, 585, 340, 585);
   line(317, 405, 320, 400);line(322, 405, 320, 400);
   
   // pour calculer la taille du rectangle selon la tension mesurée
   float histo = tension *259/1024;
   if (tension > 80) { 
    fill(255,0,0);

   }else{   
    boutonOkReglage.represente();
    fill(0,255,0);
  }
  stroke(0,0,0);
   rect(520, 280+259-histo,30,histo);  
   
   // afficher la valeur de la tension
   fill(200);textFont(font12);
   text(nfc(tension *5.00f/1023,2) + " V", 520 ,280+259+20); 
   
   // indiquer ou se trouve le seuil !
    stroke(200,200,200);strokeWeight(1);
   fill(200,150,100); textFont(font12);
    text("Seuil", 570,280+259-15);
   line(510, 280+259-20, 560, 280+259-20); 

}

Serial maConnexionArduino;

int etatConnexionArduino =0;
String messageRecu;


int tension;

public void connexionArduino() {
  
  // si la liste des ports n'est pas nulle
  if (Serial.list().length > 0){
    
    // créer la connexion avec l'arduino
    maConnexionArduino = new Serial(this, Serial.list()[0], 115200);  
    maConnexionArduino.bufferUntil(13); //met en stoke jusqu'à un retour chariot
    
    etatConnexionArduino =1; // une connexion au port est ok mais est-ce l'arduino avec le bon programme ?
    
  } else {
    etatConnexionArduino =-1;  // arduino non connecté  à l'ordinateur ?
  }
 
}

//**************************************
//          CAPTER LES EVENEMENTS SERIES
// ************************************

public void serialEvent(Serial p)
{
   // recupere le niveau de tension
   if (etatConnexionArduino ==2 && etape==1) {  
     String messageRecu = trim(maConnexionArduino.readStringUntil(13)); // 13 c'est le retour chariot et le trim l'enlève
     tension = PApplet.parseInt(messageRecu);
  }
  
  // un port a été trouvé et processing s'y est connecté il faut vérifier que c'est l'arduino bien programmé
   if (etatConnexionArduino ==1) {   
     String messageRecu = trim(maConnexionArduino.readStringUntil(13)); // 13 c'est le retour chariot et le trim l'enlève
     if (messageRecu.equals("g")) etatConnexionArduino =2;  
   }
   
   // arreter l'envoi de donnée de la tension
   if (etatConnexionArduino ==2 &&etape == 3) {
     String messageRecu = trim(maConnexionArduino.readStringUntil(13)); // 13 c'est le retour chariot et le trim l'enlève
     if (messageRecu.equals("m")) etape=4;  
    }
    
    // reception des données pour la durée
  if (etatConnexionArduino ==2 && etape == 5){
    String messageRecu = trim(maConnexionArduino.readStringUntil(13)); // 13 c'est le retour chariot et le trim l'enlève
   
    periode = PApplet.parseFloat(messageRecu)/1000.0f; 
    raz = millis(); 
  
  }
  

}
  public void settings() {  fullScreen(); }
  static public void main(String[] passedArgs) {
    String[] appletArgs = new String[] { "guitayourt_processing" };
    if (passedArgs != null) {
      PApplet.main(concat(appletArgs, passedArgs));
    } else {
      PApplet.main(appletArgs);
    }
  }
}
