import tkinter as tk
from tkinter import filedialog, messagebox
from tkinter import ttk
import shutil
import os
import json
from ftplib import FTP

class BackupApp:
    def __init__(self, root):
        self.root = root
        self.root.title("Programme de Backup")
        self.root.iconbitmap("backup.ico")

        self.source_paths = []
        self.destination_path = tk.StringVar()
        self.ftp_server = tk.StringVar()
        self.ftp_user = tk.StringVar()
        self.ftp_pass = tk.StringVar()
        self.ftp_remote_dir = tk.StringVar()
        self.backup_type = tk.StringVar(value="local")

        self.create_widgets()
        self.load_paths()

    def create_widgets(self):
        tk.Label(self.root, text="Source:").grid(row=0, column=0, padx=10, pady=10)
        self.source_listbox = tk.Listbox(self.root, selectmode=tk.MULTIPLE, height=10, width=50)
        self.source_listbox.grid(row=0, column=1, rowspan=2, padx=10, pady=10)

        tk.Button(self.root, text="Ajouter Dossier", command=self.browse_source).grid(row=0, column=2, padx=10, pady=10)
        tk.Button(self.root, text="Supprimer Dossier", command=self.remove_selected_sources).grid(row=1, column=2, padx=10, pady=10)

        tk.Label(self.root, text="Destination:").grid(row=2, column=0, padx=10, pady=10)
        tk.Entry(self.root, textvariable=self.destination_path).grid(row=2, column=1, padx=10, pady=10)
        tk.Button(self.root, text="Parcourir", command=self.browse_destination).grid(row=2, column=2, padx=10, pady=10)

        tk.Label(self.root, text="Type de Sauvegarde:").grid(row=3, column=0, padx=10, pady=10)
        tk.Radiobutton(self.root, text="Local", variable=self.backup_type, value="local").grid(row=3, column=1, padx=10, pady=10)
        tk.Radiobutton(self.root, text="FTP", variable=self.backup_type, value="ftp").grid(row=3, column=2, padx=10, pady=10)

        tk.Label(self.root, text="Serveur FTP:").grid(row=4, column=0, padx=10, pady=10)
        tk.Entry(self.root, textvariable=self.ftp_server).grid(row=4, column=1, padx=10, pady=10)

        tk.Label(self.root, text="Utilisateur FTP:").grid(row=5, column=0, padx=10, pady=10)
        tk.Entry(self.root, textvariable=self.ftp_user).grid(row=5, column=1, padx=10, pady=10)

        tk.Label(self.root, text="Mot de passe FTP:").grid(row=6, column=0, padx=10, pady=10)
        tk.Entry(self.root, textvariable=self.ftp_pass, show="*").grid(row=6, column=1, padx=10, pady=10)

        tk.Label(self.root, text="Répertoire Distant:").grid(row=7, column=0, padx=10, pady=10)
        tk.Entry(self.root, textvariable=self.ftp_remote_dir).grid(row=7, column=1, padx=10, pady=10)

        tk.Button(self.root, text="Démarrer Backup", command=self.start_backup).grid(row=8, column=1, padx=10, pady=10)

        self.progress = ttk.Progressbar(self.root, orient="horizontal", length=400, mode="determinate")
        self.progress.grid(row=9, column=0, columnspan=3, padx=10, pady=10)

    def browse_source(self):
        sources = filedialog.askdirectory(mustexist=True)
        if sources:
            self.source_paths.append(sources)
            self.source_listbox.insert(tk.END, sources)
            self.save_paths()

    def browse_destination(self):
        destination = filedialog.askdirectory(mustexist=True)
        if destination:
            self.destination_path.set(destination)
            self.save_paths()

    def remove_selected_sources(self):
        selected_indices = self.source_listbox.curselection()
        selected_paths = [self.source_listbox.get(i) for i in selected_indices]
        for path in selected_paths:
            self.source_paths.remove(path)
        for i in selected_indices[::-1]:
            self.source_listbox.delete(i)
        self.save_paths()

    def start_backup(self):
        destination = self.destination_path.get()

        if not self.source_paths or (self.backup_type.get() == "local" and not destination):
            messagebox.showerror("Erreur", "Veuillez sélectionner les répertoires source et destination.")
            return

        total_files = sum([len(files) for source in self.source_paths for _, _, files in os.walk(source)])
        self.progress["maximum"] = total_files
        self.progress["value"] = 0

        try:
            if self.backup_type.get() == "local":
                for source in self.source_paths:
                    self.incremental_backup(source, destination)
            elif self.backup_type.get() == "ftp":
                ftp_server = self.ftp_server.get()
                ftp_user = self.ftp_user.get()
                ftp_pass = self.ftp_pass.get()
                ftp_remote_dir = self.ftp_remote_dir.get()
                if not ftp_server or not ftp_user or not ftp_pass or not ftp_remote_dir:
                    messagebox.showerror("Erreur", "Veuillez entrer les informations FTP et le répertoire distant.")
                    return
                for source in self.source_paths:
                    self.ftp_backup(source, ftp_server, ftp_user, ftp_pass, ftp_remote_dir)
            messagebox.showinfo("Succès", "Sauvegarde terminée avec succès.")
        except Exception as e:
            messagebox.showerror("Erreur", f"Une erreur est survenue: {e}")

    def incremental_backup(self, source, destination):
        for root, dirs, files in os.walk(source):
            relative_path = os.path.relpath(root, source)
            dest_dir = os.path.join(destination, os.path.basename(source), relative_path)
            if not os.path.exists(dest_dir):
                os.makedirs(dest_dir)
            for file in files:
                source_file = os.path.join(root, file)
                dest_file = os.path.join(dest_dir, file)
                if not os.path.exists(dest_file) or os.path.getmtime(source_file) > os.path.getmtime(dest_file):
                    shutil.copy2(source_file, dest_file)
                self.progress["value"] += 1
                self.root.update_idletasks()

    def ftp_backup(self, source, ftp_server, ftp_user, ftp_pass, ftp_remote_dir):
        ftp = FTP(ftp_server)
        ftp.login(user=ftp_user, passwd=ftp_pass)
        ftp.set_pasv(True)  # Forcer le mode passif
        ftp.cwd('/')

        # Créer le répertoire distant s'il n'existe pas
        try:
            ftp.mkd(ftp_remote_dir)
        except Exception as e:
            if not str(e).startswith('550'):
                raise

        ftp.cwd(ftp_remote_dir)

        for root, dirs, files in os.walk(source):
            relative_path = os.path.relpath(root, source).replace("\\", "/")
            for dir in dirs:
                dir_path = os.path.join(relative_path, dir).replace("\\", "/")
                try:
                    ftp.mkd(dir_path)
                except Exception as e:
                    if str(e).startswith('550'):
                        pass
                    else:
                        raise
            for file in files:
                file_path = os.path.join(root, file).replace("\\", "/")
                with open(file_path, 'rb') as f:
                    ftp.storbinary("STOR {}".format(os.path.join(relative_path, file).replace('\\', '/')), f)
                self.progress["value"] += 1
                self.root.update_idletasks()

        ftp.quit()

    def save_paths(self):
        data = {
            "source_paths": self.source_paths,
            "destination_path": self.destination_path.get(),
            "ftp_server": self.ftp_server.get(),
            "ftp_user": self.ftp_user.get(),
            "ftp_pass": self.ftp_pass.get(),
            "ftp_remote_dir": self.ftp_remote_dir.get(),
            "backup_type": self.backup_type.get()
        }
        with open("paths.json", "w") as file:
            json.dump(data, file)

    def load_paths(self):
        if os.path.exists("paths.json"):
            with open("paths.json", "r") as file:
                data = json.load(file)
                self.source_paths = data.get("source_paths", [])
                self.destination_path.set(data.get("destination_path", ""))
                self.ftp_server.set(data.get("ftp_server", ""))
                self.ftp_user.set(data.get("ftp_user", ""))
                self.ftp_pass.set(data.get("ftp_pass", ""))
                self.ftp_remote_dir.set(data.get("ftp_remote_dir", ""))
                self.backup_type.set(data.get("backup_type", "local"))
                for path in self.source_paths:
                    self.source_listbox.insert(tk.END, path)

if __name__ == "__main__":
    root = tk.Tk()
    app = BackupApp(root)
    root.mainloop()
