#importation des librairies
import math
import serial
import time
import sys

import numpy as np

import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
from matplotlib.figure import Figure
import matplotlib.animation as animation
from matplotlib import style

from tkinter import *
from tkinter.filedialog import askopenfilename
import tkinter as tk






#définition de la police
LARGE_FONT=("Verdana",16)
#on détermine le style du graphique (avec fond gris)
style.use("ggplot")



     ##### ESSAI FIGURE EN TEMPS RÉEL #####

# #on définit la taille de la figure
# f = Figure(figsize = (5,5), dpi = 100)
# #ajout de la figure avec subplot (111 = figure 1 par 1 et figure numéro 1)
# a = f.add_subplot(111)
# #on renseignes les données
#
#
# def animate(i):
#     pullData = open("data","r").read()
#     dataList = pullData.split('\n')
#     xList = []
#     for eachLine in dataList:
#         if len(eachLine) >1:
#             x=eachLine
#             xList.append(int(x))
#     a.clear()
#     a.plot(xList)



#Création de la classe Graphique
class Graphique(tk.Tk):


    #initialisateur appelé automatiquement après qu'un objet ait été créé
    #on donne l'état de départ
    #accepet des paramètres, self doit être le premier paramètre
    #self  = l'objet cible, c'est une variable qui contient une référence vers l'objet en cours de création
    def __init__(self, *args, **kwargs):


         #on initalise la fenêtre
         tk.Tk.__init__(self, *args, **kwargs)
         # défintion du titre
         tk.Tk.wm_title(self, "Graphique")

         container = tk.Frame(self)
         container.pack(side="top", fill="both", expand = True)
         container.grid_rowconfigure(0,weight=1)
         container.grid_columnconfigure(0,weight=1)

         self.frames = {}

         for F in (StartPage, PageOne, PageTwo, PageThree):
             frame = F(container,self)
             self.frames[F] = frame
             frame.grid(row=0, column=0, sticky="nsew")
         self.show_frame(StartPage)

    def show_frame(self,cont):
         frame = self.frames[cont]
         frame.tkraise()


#page d'accueil
class StartPage(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self,parent)
        #inscription
        label = tk.Label(self,text="Bienvenue", font=LARGE_FONT)
        #placement du label à la ligne 2, colonne 6
        label.grid(row = 2, column=6)
        #on créé un bouton qui va permettre de rediriger vers l'affichage de la température sur une autre page
        button = tk.Button(self, text = "Afficher la température", command = lambda: controller.show_frame(PageOne))
        #Placement du bouton
        button.grid(row = 3, column = 6)
        #bouton qui redirige vers la page de control des Leds
        button2 = tk.Button(self, text = "Contrôler les LEDs", command=lambda: controller.show_frame(PageTwo))
        #placement du bouton
        button2.grid(row=4, column = 6)
        #bouton qui redirige vers la page d'un formulairre
        button3 = tk.Button(self, text = "Remplir un formulaire", command=lambda: controller.show_frame(PageThree))
        button3.grid(row=5, column = 6)
        #en haut, on place un menu
        zoneMenu = Frame(self, borderwidth=3, bg='#557788')
        zoneMenu.grid(row=0, column = 0)
        #on créé chaque onglet du menu :

        # Création de l'onglet Fichier
        menuFichier = Menubutton(zoneMenu, text = 'Fichier', width='20', borderwidth=2, bg='gray', activebackground='darkorange', relief = RAISED)
        menuFichier.grid(row=0, column=0)

        # Création de l'onglet Edition
        menuEdit = Menubutton(zoneMenu, text='Editer', width='20', borderwidth=2, bg='gray', activebackground='darkorange',relief = RAISED)
        menuEdit.grid(row=0,column=1)

        # Création de l'onglet Format
        menuFormat = Menubutton(zoneMenu, text='Format', width='20', borderwidth=2, bg='gray', activebackground='darkorange',relief = RAISED)
        menuFormat.grid(row=0,column=2)

        menuAffichage = Menubutton(zoneMenu, text='Affichage', width='20', borderwidth=2, bg='gray', activebackground='darkorange',relief = RAISED)
        menuAffichage.grid(row=0,column=3)


        #création des fonctions servant aux différents onglets
        # fonctions de l'onglet Affichage, elles changent juste la couleur du fonc
        def fondClair():
            self.configure(bg = 'pink')

        def fondSombre():
            self.configure(bg= 'black')

        # création d'un menu déroulant
        Menu(menuAffichage,tearoff=0)
        menuDeroulant1 = Menu(menuAffichage)
        menuDeroulant1.add_command(label='Fond clair', command = fondClair)
        menuDeroulant1.add_command(label='Fond sombre', command = fondSombre)

        # attribution du menu déroulant au menu menuAffichage
        menuAffichage.configure(menu=menuDeroulant1)




        #fonctions de l'onglet Fichier
        #on peut ouvrir un fichier, afficher un message

        #on ouvre un fichier de l'ordinateur
        def openFile():
            file = askopenfilename(title="Choisir un fichier à ouvrir",filetypes=[("PNG image", ".png"), ("GIF image", ".gif"), ("All files", ".*")])
            print( file )

        #cette fonction afficher seulement "Menu Clicked" sur le terminal
        def doSomething(fenetre):
            print("Menu clicked")

        #cette fonction affiche un message sur l'interface
        #il est seulement marqué ce qu'ily  a entre parenthèses
        def doAbout(fenetre):
            messagebox.showinfo("My title", "My message")
#
        #affichage du menu Fichier
        Menu(menuFichier, tearoff=0)
        menuDeroulant2=Menu(menuFichier)
        #on détaille chaque possibilité de l'onglet Fichier
        #chaque possibilité est reliée à une fonction
        menuDeroulant2.add_command(label="New", command= doSomething)
        menuDeroulant2.add_command(label="Open", command= openFile)
        menuDeroulant2.add_command(label="Save", command= doSomething)
        menuDeroulant2.add_separator()
        menuDeroulant2.add_command(label="Exit", command=self.quit)

        menuFichier.configure(menu=menuDeroulant2)


#Deuxième page de l'interface qui va permettre d'afficher la température
class PageOne(tk.Frame) :
    #fonction d'initialisation
    def __init__(self,parent,controller):
        tk.Frame.__init__(self,parent)
        #on affiche un label
        label = tk.Label(self, text="Graphe de la température", font=LARGE_FONT)
        label.pack(pady=10, padx=10)


        # res=entree1.get()
        # print(res)
        #fonction de controle qui va permettre d'actionner la prise de température et son affichage
        def control():
            #on précise le port, ici l'arduino est /dev/ttyACM0
            ser = serial.Serial('/dev/ttyACM0',9600);
            print(ser)

            #Réception et stockage des données
            #on prend ici en compte  données

            #cette fonction se déclenche lorsque l'on appuie sur le bouton Actionner
            def getEntry():
                #On récupère le texte entré par l'utilisateur afin de savoir combien de points il veut sur sa courbe
                res = entree1.get()
                print(res)

                #on initialise un tableau dans lequel les données vont arriver
                rawdata =[]
                compt = 0;

                #on remplit le tableau avec les valeurs du fichier texte
                #on prend on considérations les n valeurs, n étant le nombre décidé par l'utilisateur
                while (compt<int(res)):
                    #on rremplit le tableau rawdata par les valeurs du fichier texte
                    rawdata.append(str(ser.readline()))
                     #on rajoute 1 au compteur jusqu'a ce qu'il atteigne res (la valeur décidée par l'utilisateur)
                    compt+=1
                #on affiche le tableau rawdata sur le terminal
                print(rawdata);

               #les valeurs sur le terminal s'affiche de cette manière :
               #["b'val1\\n'", "b'val2\\n'", "b'val\\n'"]
               #On veut un tableau plus clair, sans le b ni le \\n
               #Pour cela, on écrit la fonction nettoie qui va permettre d'afficher un tableau :['val1', 'val2', 'val3']
                def nettoie(L):
                    #on initialise un nouveau tableau
                    newL=[]
                    #jusqu'a ce qu'on atteigne la fin de la longueur de notre tableau rawdata
                    for i in range(len(L)):
                        #on réduit le b et le \\n
                        temp=L[i][2:]
                        #on remplit le nouveau tableau newL avec la valeur "nettoyée"
                        newL.append(temp[:-5])
                    #on retourne le nouveau tableau
                    return newL

                #on appelle la fonction nettoie
                cleandata=nettoie(rawdata)
                #on écrit le nouveau tableau dans le terminal
                print(cleandata)

                #on veut maintenant remplir le fichier texte des valeurs prises
                def write(L):
                    #on ouvre le fichier data.txt en mode écriture (w)
                    file = open("data.txt", mode="w")
                    #on parcourt notre tableau et on ajoute chaque case à chaque ligne du fichierr
                    for i in range(len(L)):
                        file.write(L[i]+'\n')
                    #on ferme le fichier
                    file.close()

                #on appelle la fonction qui va permettre d'écrire dans le fichier texte
                write(cleandata)

                #on définit la taille de la figure
                f = Figure(figsize = (1,0.5), dpi = 25)

                #ajout de la figure avec subplot (111 = figure 1 par 1 et figure numéro 1)
                a = f.add_subplot(111)
                #oon affiche la figure, on prend en compte le fichier data.txt
                #ne pas oublier le delimiter, ce qui va séparer chaque valeur, dans ce cas ci c'est un retour à la ligne, donc un espace
                a.plot(np.loadtxt("data.txt",delimiter=' ',unpack=True))

               #on affiche le Graphe avec en paramètre notre figure f définie avant
               #on appelle canvas
                canvas = FigureCanvasTkAgg(f, self)
                canvas.draw()
               #on détermine l'emplacement du graphe s sur la figure
                canvas.get_tk_widget().pack(side = tk.TOP, fill=tk.BOTH)
                #on affiche un menu en bas de la page avec diverses focntionnalités donc la possibilité d'eregistrer le fichier
                toolbar = NavigationToolbar2Tk(canvas, self)
                toolbar.update()
                #on place la figure, ici elle est placée sur la gauche
                canvas._tkcanvas.pack(side = tk.LEFT, fill=tk.BOTH, expand= True)



            #on affiche un texte avec label pour demander à l'utilisateur combien de points il souhaite mesurer
            texte1 = tk.Label(self, text = "Combien de points souhaitez-vous mesurer ? ", font=LARGE_FONT)
            #on place ce texte
            texte1.pack()
            #espace où l'utilisateur peut rentrer la valeur qu'il souhaite
            #petit problème de placement, cette case se place tout en bas de la page et pas nécessairement à coté du label
            entree1 = Entry()
            #on place cette entrée
            entree1.pack()
            #on met en place un bouton valider où l'utilisateur vaide son choix
            #ce bouton se redirigé vers la fonction getEntry() qui va récupérer ce qui a été indiqué dans la case d'écriture
            valid = tk.Button(self, text="Valider", command=getEntry)
            valid.pack()

        #on place un bouton Actionner
        #lorsque ce bouton est enclenché, il actionne la fonction control qui va réaliser ce qui a été expliqué avant
        #ainsi, on demandera à l'utilisateur combien de points il souhaite
        #puis en appuyant sur le bouton validé, une courbe s'affichera
        #ceci se repète tant que l'on appuie sur le bouton Actionner
        boutonAction = tk.Button(self, text = "Actionner", command = control)
        #placement du bouton Actionner
        boutonAction.pack()
        #un bouton Revenir à l'accueil permet de rediriger l'utilisateur vers la première page que l'on a appelé StartPage
        button1 = tk.Button(self,text = "Revenir à l'accueil", command = lambda: controller.show_frame(StartPage))
        button1.pack()
        #un bouton Controler les Leds permet de rediriger l'utilisateur vers une nouvelle page que l'on a appelé Page Two
        button2 = tk.Button(self,text = "Controler les LEDs", command = lambda: controller.show_frame(PageTwo))
        button2.pack()




        # ##ICI SE TROUVE UNE FONCTION QUI PERMET DE CALCULER LA MOYENNE DES VALEURS DU FICHIER TEXTE
        # # Ouvrir le fichier en lecture seule
        # file = open('data.txt', "r")
        # # utiliser readlines pour lire toutes les lignes du fichier
        # # La variable "lignes" est une liste contenant toutes les lignes du fichier
        # lines = file.readlines()
        # # fermez le fichier après avoir lu les lignes
        # file.close()
        # # on additionne chaque ligne grâce à nbr pour obtenir la moyenne
        # nbr = 0
        # # long permet de calculer la longueur du fichier
        # long = 0
        # # Itérer sur les lignes
        # for line in lines:
        #     #nbr prend la valeur de chaque ligne du fichier et l'ajoute à son compteur
        #     nbr += float(line.strip())
        #     #on calcule le nombre de lignes du fichier, à chaque itération, long prend +1
        #     long+=1
        # #la moyenne vaut toutes la valeurs additionnées entre elles, divisé par le nombre de valeurs (long)
        # moy=nbr/long
        # #on affiche la moyenne grâce à un label
        # moyenne  = tk.Label(self, text=("La moyenne de température est",moy), font=LARGE_FONT)
        # moyenne.pack()






#PAGE POUR CONTROLER LES LEDS
class PageTwo(tk.Frame):
    #initialisation de la page
    def __init__(self, parent, controller):
        tk.Frame.__init__(self,parent)
        #on affiche un label
        label = tk.Label(self, text="Controler les LEDs", font=LARGE_FONT)
        label.pack(pady=10, padx=10)
        #un bouton pour rediriger vers la page d'accueil appelée Start Page dans le code
        button1 = tk.Button(self,text = "Revenir à l'accueil", command = lambda: controller.show_frame(StartPage))
        button1.pack()
        #Bouton pour rediriger l'utilisateur vers la page permettant d'afficher la température, appelée PageOne
        button2 = tk.Button(self,text = "Afficher la température", command = lambda: controller.show_frame(PageOne))
        button2.pack()

        #on indique le port utilisé
        ser = serial.Serial('/dev/ttyACM0',9600)

        #une fonction qui permet d'enclencher la led branchée
        def on_button():
            ser.write(b'1')

        #une fonction qui permet d'éteindre la led
        def off_button():
            ser.write(b'0')


        #on définit un bouton
        Button = tk.Button
        #un premier bouton qui lorsqu'on l'active déclenche la fonction on_button permettant d'allumer la led
        btn = Button(self, text="ON", command = on_button)
        #un deuxième bouton qui lorsqu'on l'active déclenche la fonction off_button permettant d'éteindre la led
        btn1 = Button(self,text="OFF", command = off_button)
        #on place ces boutons
        btn.pack()
        btn1.pack()



#Troisième Page qui permet d'afficher un formulaire
class PageThree(tk.Frame):
    #initialisation de la page
    def __init__(self,parent,controller):
        tk.Frame.__init__(self,parent)
        #on affiche un label qui écrit Formulaire en titre
        label = tk.Label(self, text = "Formulaire", font = LARGE_FONT)
        label.pack(pady=10, padx=10)
        #un bouton qui permet de revenir à la page d'accueil, StartPage
        button1 = tk.Button(self, text="Back To Home", command=lambda: controller.show_frame(StartPage))
        button1.pack()

        #on laisse une entrée pour l'utilisateur rentre son nom
        nom = Label(self, text="Nom")
        e0 = Entry(self)
        #on laisse une entrée pour l'utilisateur rentre son prénom
        prenom = Label(self, text="Prenom")
        e = Entry(self)
        nom.pack()
        #on place tous ces champs sur la page
        e0.pack()
        prenom.pack()
        e.pack()



#Notre interface prend le nom de la classe principale créée au début, c'est à dire Graphique
app = Graphique()
#on affiche notre interface avec l'instruction mainloop
app.mainloop()





##### !!! si lorsque l'on lance le programme python , l'erreur suivante survient -> ValueError: could not convert string to float: ''
#ouvrir le fichier texte et vérifier qu'une ligne ne soit pas vide, la remplacer avec un chiffre au hasard
#lors du déclenchement du bouton action, ces valeurs seront remplacées par les valeurs mesurées
