from tkinter import *
from tkinter import messagebox
import zipfile
import os
import ctypes
import pathlib
import shutil

# Increase Dots Per inch so it looks sharper
ctypes.windll.shcore.SetProcessDpiAwareness(True)


root = Tk()
# set a title for our file explorer main window
root.title('Simple Explorer')

root.grid_columnconfigure(1, weight=1)
root.grid_rowconfigure(1, weight=1)
clipboard_path = ''
def unzipItem():
    try:
        picked = list.get(list.curselection()[0])
        if not picked.lower().endswith(".zip"):
            print("Selected file is not a .zip archive.")
            return
        zip_path = os.path.join(currentPath.get(), picked)
        extract_dir = os.path.join(currentPath.get(), picked[:-4])  # remove .zip

        with zipfile.ZipFile(zip_path, 'r') as zip_ref:
            os.makedirs(extract_dir, exist_ok=True)
            zip_ref.extractall(extract_dir)

        confirm = messagebox.askyesno("Delete Zip?", f"Delete original zip file '{picked}' after extraction?")
        if confirm:
            os.remove(zip_path)
            print(f"Unzipped and deleted '{picked}'")
        else:
            print(f"Unzipped '{picked}' without deleting.")
        
        pathChange()
    except Exception as e:
        print(f"Unzip error: {e}")

def pathChange(*event):
    # Get all Files and Folders from the given Directory
    directory = os.listdir(currentPath.get())
    # Clearing the list
    list.delete(0, END)
    # Inserting the files and directories into the list
    for file in directory:
        list.insert(0, file)

def copyItem():
    global clipboard_path
    try:
        picked = list.get(list.curselection()[0])
        clipboard_path = os.path.join(currentPath.get(), picked)
        print(f"Copied: {clipboard_path}")
    except Exception as e:
        print(f"Copy error: {e}")

def pasteItem():
    global clipboard_path
    if not clipboard_path:
        return
    try:
        dest = os.path.join(currentPath.get(), os.path.basename(clipboard_path))
        if os.path.isfile(clipboard_path):
            shutil.copy2(clipboard_path, dest)
        else:
            shutil.copytree(clipboard_path, dest)
        print(f"Pasted: {dest}")
        pathChange()
    except Exception as e:
        print(f"Paste error: {e}")

def changePathByClick(event=None):
    # Get clicked item.
    picked = list.get(list.curselection()[0])
    # get the complete path by joining the current path with the picked item
    path = os.path.join(currentPath.get(), picked)
    # Check if item is file, then open it
    if os.path.isfile(path):
        print('Opening: '+path)
        os.startfile(path)
    # Set new path, will trigger pathChange function.
    else:
        currentPath.set(path)

def goBack(event=None):
    # get the new path
    newPath = pathlib.Path(currentPath.get()).parent
    # set it to currentPath
    currentPath.set(newPath)
    # simple message
    print('Going Back')

def deleteItem():
    try:
        picked = list.get(list.curselection()[0])
        path = os.path.join(currentPath.get(), picked)
        confirm = messagebox.askyesno("Confirm Delete", f"Delete '{picked}'?")
        if not confirm:
            return
        if os.path.isfile(path):
            os.remove(path)
        
        else:
            shutil.rmtree(path)
        pathChange()
        print(f"Deleted: {path}")
    except Exception as e:
        print(f"Error deleting: {e}")

def open_rename_popup():
    try:
        picked = list.get(list.curselection()[0])
    except:
        return
    global rename_top
    rename_top = Toplevel(root)
    rename_top.geometry("250x150")
    rename_top.title("Rename")
    rename_top.resizable(False, False)
    Label(rename_top, text=f"Rename '{picked}' to:").pack(pady=10)
    rename_entry = Entry(rename_top)
    rename_entry.pack(pady=5)
    Button(rename_top, text="Rename", command=lambda: renameItem(picked, rename_entry.get())).pack(pady=10)
def renameItem(old_name, new_name):
    try:
        old_path = os.path.join(currentPath.get(), old_name)
        new_path = os.path.join(currentPath.get(), new_name)
        os.rename(old_path, new_path)
        print(f"Renamed '{old_name}' to '{new_name}'")
        rename_top.destroy()
        pathChange()
    except Exception as e:
        print(f"Rename error: {e}")
def open_popup():
    global top
    top = Toplevel(root)
    top.geometry("250x150")
    top.resizable(False, False)
    top.title("Child Window")
    top.columnconfigure(0, weight=1)
    Label(top, text='Enter File or Folder name').grid()
    Entry(top, textvariable=newFileName).grid(column=0, pady=10, sticky='NSEW')
    Button(top, text="Create", command=newFileOrFolder).grid(pady=10, sticky='NSEW')

def newFileOrFolder():
    # check if it is a file name or a folder
    if len(newFileName.get().split('.')) != 1:
        open(os.path.join(currentPath.get(), newFileName.get()), 'w').close()
    else:
        os.mkdir(os.path.join(currentPath.get(), newFileName.get()))
    # destroy the top
    top.destroy()
    pathChange()

top = ''

# String variables
newFileName = StringVar(root, "File.dot", 'new_name')
currentPath = StringVar(
    root,
    name='currentPath',
    value=pathlib.Path.cwd()
)
# Bind changes in this variable to the pathChange function
currentPath.trace('w', pathChange)

Button(root, text='Folder Up', command=goBack).grid(
    sticky='NSEW', column=0, row=0
)

# Keyboard shortcut for going up
root.bind("<Alt-Up>", goBack)

Entry(root, textvariable=currentPath).grid(
    sticky='NSEW', column=1, row=0, ipady=10, ipadx=10
)

# List of files and folder
list = Listbox(root)
list.grid(sticky='NSEW', column=1, row=1, ipady=10, ipadx=10)

# List Accelerators
list.bind('<Double-1>', changePathByClick)
list.bind('<Return>', changePathByClick)


# Menu
menubar = Menu(root)
# Adding a new File button
menubar.add_command(label="Add File or Folder", command=open_popup)
# Adding a quit button to the Menubar
menubar.add_command(label="Quit", command=root.quit)
menubar.add_command(label="Delete Selected", command=deleteItem)
menubar.add_command(label="Copy", command=copyItem)
menubar.add_command(label="Paste", command=pasteItem)
menubar.add_command(label="Rename", command=open_rename_popup)
menubar.add_command(label="Unzip .zip", command=unzipItem)


# Make the menubar the Main Menu
root.config(menu=menubar)

# Call the function so the list displays
pathChange('')
# run the main program
root.mainloop()
