# Interface utilisateur permettant d'entrer, trouver et mettre à jour
# des informations dans la table Client de la base de données Librairie.sq3

# Importation de modules:
import sqlite3
from tkinter import *
from tkinter.messagebox import *        # module permettant de créer des fenetres intempestives


########## Classe de l'application ###########

class Application(Tk):
    "Classe de l'application principale"

    def __init__(self, db):
        "Constructeur de l'objet Application"
        Tk.__init__(self)
        self.title("Gestionnaire de base de données")

        # Boutons d'exécution de requetes:
        self.boutons = PanedWindow(self, orient = HORIZONTAL)
        self.boutons.grid(columnspan = 2)
        self.boutons.add(Button(self, text="Rechercher", command = self.rechercher))
        self.boutons.add(Button(self, text="Ajouter", command = self.ajouter))
        self.boutons.add(Button(self, text="Actualiser", command = self.actualiser))
        self.boutons.add(Button(self, text="Effacer", command = self.detruire))
        self.boutons.add(Button(self, text="Mise à zéro", command = self.vider))
        self.boutons.add(Button(self, text="Aide", command = self.aider))

        # Liste des noms des nomChamps d'un client:
        nomChamps = ['Nom', 'Adresse', 'Ville', 'Canton', 'NoPostal']

        # Dictionnaire reliant chaque nom de champ (clé) à la zone de
        # saisie de texte correspondante (valeur)
        self.champs = {}

        # Création d'une zone de saisie de texte pour chaque champ:
        for i in range(len(nomChamps)):
            # positionner la zone de texte avec son étiquette de texte:
            texte = Label(self, text = nomChamps[i] + ":", font=("Arial", 14))
            texte.grid(row = i+1, column = 0)
            saisie = Entry(self, font = "Courier 12")
            saisie.grid(row = i+1, column = 1, padx=5)

            # associer le nom de chaque champ à sa zone de saisie correspondant:
            self.champs[nomChamps[i]] = saisie

        # Bouton de fermeture:
        Button(self, text="Quitter", command=self.fermer).grid(row=i+2, column = 1, padx=5, sticky=E)

        # Identifiant du client actuellement affiché
        self.ID = ""

        # Ouverture de connexion et définition du curseur
        self.conn = sqlite3.connect(db)             # Connexion à la BD
        self.conn.row_factory = sqlite3.Row         # Retourner les enregistrements sous forme de tableau associatif
        self.cur = self.conn.cursor()               # Initialisation du curseur

    def rechercher(self):
        """Recherche un client selon les critères entrés"""

        # liste des noms de champs non vides:
        criteres = []

        for c in self.champs:
            if self.champs[c].get() != "":
                criteres.append(c)

        # construction de la requete:
        if len(criteres) > 0:
            requete = "SELECT * FROM Client WHERE "

            for c in criteres:
                requete += c + " = '" + self.champs[c].get() + "' AND "

            requete = requete[:-5]          # effacer le dernier AND

            try:
                self.cur.execute(requete)
                
            except TypeError as e:
                print("Erreur dans la requete exécutée:")
                print(requete)
                print(e)
                
            else: # gestion du (des) résultats

                results = self.cur.fetchall()   # récupération des résultats sous forme de liste d'objet Row
                if not results:
                    showinfo("Inconnu", "Aucun résultat ne satisfait le(s) critère(s) entré(s) !")
                elif len(results) > 1:
                    showwarning("Plusieurs résultats", "Plusieurs résultats vérifient le(s) critère(s) ! Affinez votre recherche !")
                else:
                    resultat= results[0]        # récupération de l'unique résultat
                    self.vider()
                    for c in self.champs:
                        self.champs[c].insert(INSERT, str(resultat[c]))
                    self.ID = resultat["ClientID"]  # récupération de l'identifiant du client pour d'éventuelles mises à jour
        else:
            showwarning("Attention !", "La recherche doit etre effectuée sur au moins un critère !")
            
               

    def ajouter(self):
        """Ajout d'un client dans la base de données"""

        # requete à envoyer à la BD
        debutRequete = "INSERT INTO Client("
        finRequete = "VALUES("

        # flag permettant de déterminer si tous les nomChamps ont été remplis
        flag = 1

        for c in self.champs.keys():

            val = self.champs[c].get().replace("'", "''")  # récupérer la valeur du champ entrée
                                                            # en remplaçant les guillemets simples
                                                            # en guillemets doubles
            
            # si un champ est vide, retourner un message d'erreur dans
            # une fenetre intempestive (pop-up)
            if val == "":
                flag = 0
                showerror("Erreur", "Tous les nomChamps doivent etre remplis !")
                break

            # sinon poursuivre l'écriture de la requete
            else:
                debutRequete += c + ", "
                finRequete += "'"+val + "', "

        # si tous les nomChamps ont été saisis, terminer la création de la requete:
        if flag:
            debutRequete = debutRequete[:-2] + ") "
            finRequete = finRequete[:-2] + ")"
            requete = debutRequete + finRequete
            if askyesno("Attention !", "Voulez-vous vraiment enregistrer ce client ?"):
                try:
                    self.cur.execute(requete)
                except TypeError as e:
                    print("Erreur dans la requete exécutée:")
                    print(requete)
                    print(e)
                else:
                    self.conn.commit()
                    showinfo("Sauvegarde", "Le client "+self.champs['Nom'].get()+" a été sauvegardé avec succès !")
                    self.vider()
 
            

    def actualiser(self):
        """Met à jour un enregistrement"""

        return None

        
    def detruire(self):
        """Détruit un enregistrement"""

        return None


    def vider(self):
        "Vide le contenu de chaque saisie de texte"

        for c in self.champs:
            self.champs[c].delete(0, END)

        self.ID = ""



    def aider(self):
        "Affiche un message d'aide à l'utilisateur"

        showinfo("Aide", """Cliquez sur 'Rechercher' pour trouver un enregistrement.

Cliquez sur 'Ajouter' pour sauvegarder un enregistrement.

Cliquez sur 'Actualiser' pour mettre à jour un enregistrement existant.

Cliquez sur 'Effacer' pour détruire un enregistrement existant.

Cliquez sur 'Mise à zéro' pour vider tous les champs.""")

    def fermer(self):
        "Ferme curseur, connexion et détruit la fenetre"
        self.cur.close()                # Fermeture du curseur
        self.conn.close()               # Fermeture de la connexion
        self.destroy()                  # Destruction de la fenetre

        
########## Programme principal ###########

Application('Librairie.sq3').mainloop()
