import tkinter as tk
from tkinter import filedialog, messagebox, simpledialog
from PIL import Image
import cv2

# --- FONCTIONS TECHNIQUES CONSERVÉES ---

def convertToBinary(data):
    newdata = []
    for i in data:
        newdata.append(format(ord(i), '08b'))
    return newdata

def encodepixels(pix, data):
    datalist = convertToBinary(data)
    lendata = len(datalist)
    image_data = iter(pix)
    for i in range(lendata):
        # On extrait 3 pixels (9 valeurs RGB) pour cacher 8 bits + 1 bit de contrôle
        pix_group = [value for value in image_data.__next__()[:3] + image_data.__next__()[:3] + image_data.__next__()[:3]]
        for j in range(0, 8):
            if (datalist[i][j] == "0" and pix_group[j] % 2 != 0):
                pix_group[j] -= 1
            elif (datalist[i][j] == "1" and pix_group[j] % 2 == 0):
                if (pix_group[j] != 0):
                    pix_group[j] -= 1
                else:
                    pix_group[j] += 1
        
        # Bit de fin de message (pix[-1])
        # 0 = continuer, 1 = terminer
        if (i == lendata - 1):
            if (pix_group[-1] % 2 == 0):
                if(pix_group[-1] != 0):
                    pix_group[-1] -= 1
                else:
                    pix_group[-1] += 1
        else:
            if (pix_group[-1] % 2 != 0):
                pix_group[-1] -= 1
        
        pix_tuple = tuple(pix_group)
        yield pix_tuple[0:3]
        yield pix_tuple[3:6]
        yield pix_tuple[6:9]

def encode_image(new_image, data):
    w = new_image.size[0]
    (x, y) = (0, 0)
    for pixel in encodepixels(new_image.getdata(), data):
        new_image.putpixel((x, y), pixel)
        if (x == w - 1):
            x = 0
            y += 1
        else:
            x += 1

# --- SYSTÈME DE SÉLECTION DE FICHIERS ---

def select_file(title, save=False):
    root = tk.Tk()
    root.withdraw()
    ftypes = [
        ("Images", "*.png *.PNG *.jpg *.JPG *.jpeg *.JPEG *.bmp *.BMP"),
        ("Tous les fichiers", "*.*")
    ]
    if save:
        path = filedialog.asksaveasfilename(title=title, defaultextension=".png", filetypes=[("PNG", "*.png")])
    else:
        path = filedialog.askopenfilename(title=title, filetypes=ftypes)
    root.destroy()
    return path

# --- ACTIONS PRINCIPALES ---

def encode():
    img_path = select_file("Sélectionnez l'image source")
    if not img_path: return

    # Utilisation d'une boîte de dialogue pour le texte
    root = tk.Tk()
    root.withdraw()
    data = simpledialog.askstring("Message Secret", "Entrez le texte à cacher :")
    root.destroy()
    
    if not data:
        messagebox.showwarning("Annulé", "Le message est vide.")
        return

    image = Image.open(img_path, 'r')
    new_image = image.copy()
    encode_image(new_image, data)

    out_path = select_file("Enregistrer l'image encodée", save=True)
    if out_path:
        new_image.save(out_path)
        messagebox.showinfo("Succès", f"Message caché enregistré dans :\n{out_path}")

def decode():
    img_path = select_file("Sélectionnez l'image à décoder")
    if not img_path: return

    image = Image.open(img_path, 'r')
    data = ''
    image_data = iter(image.getdata())
    
    # Affichage optionnel via OpenCV comme dans votre code
    temp_img = cv2.imread(img_path)
    cv2.imshow("Image en cours de decodage (pressez une touche)", temp_img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

    try:
        while True:
            pixels = [value for value in image_data.__next__()[:3] +
                                        image_data.__next__()[:3] +
                                        image_data.__next__()[:3]]
            binary_string = ''
            for i in pixels[:8]:
                if (i % 2 == 0):
                    binary_string += '0'
                else:
                    binary_string += '1'
            
            data += chr(int(binary_string, 2))
            if (pixels[-1] % 2 != 0): # Fin de message détectée
                break
        
        messagebox.showinfo("Message Décodé", f"Le message est :\n\n{data}")
    except StopIteration:
        messagebox.showerror("Erreur", "Fin de l'image atteinte sans trouver de fin de message.")

# --- MENU PRINCIPAL ---

def main():
    menu = tk.Tk()
    menu.title("Stéganographie Texte")
    menu.geometry("350x200")
    
    tk.Label(menu, text="Outil de Stéganographie LSB", font=('Arial', 11, 'bold'), pady=20).pack()
    
    tk.Button(menu, text="1. Cacher du texte (Encode)", command=encode, width=30, bg="#E3F2FD").pack(pady=5)
    tk.Button(menu, text="2. Lire un secret (Decode)", command=decode, width=30, bg="#F1F8E9").pack(pady=5)
    
    menu.mainloop()

if __name__ == "__main__":
    main()