import tkinter
import os
import subprocess
import sys

from voussoirkit import pathclass
from voussoirkit import vlogging

log = vlogging.get_logger(__name__, 'pgui')

BUTTON_WIDTH = 12

MAIN_BG = '#000'
MAIN_FG = '#FFF'
ENTRY_BG = '#222'
BUTTON_BG_NORMAL = '#000'
BUTTON_BG_HIGHLIGHT = '#00aa00'
FOLDER_EMOJI = '\U0001F4C1'

PGUI_FOLDER = pathclass.Path(__file__).parent.with_child('PGUI')

def load_programs():
    log.debug('Loading programs from %s.', PGUI_FOLDER.absolute_path)
    shortcuts = PGUI_FOLDER.glob_files('*.lnk')
    shortcuts.sort()
    return shortcuts

class PGUILauncher(tkinter.Frame):
    def __init__(self, parent):
        super().__init__(parent, bg=MAIN_BG)

        self._init_upper_controls()
        self._init_buttons()

        self.ready_to_launch = None

        self.pack()
        self.update()

    def _init_buttons(self):
        shortcuts = load_programs()

        # This keeps the grid looking mostly square regardless of input count.
        column_count = int(len(shortcuts) ** 0.5)
        column_count = max(column_count, 1)

        self.buttons = []

        for (index, shortcut) in enumerate(shortcuts):
            button = tkinter.Button(
                self,
                bg=BUTTON_BG_NORMAL,
                command=lambda sc=shortcut: self.launch_program(sc),
                fg=MAIN_FG,
                height=2,
                text=shortcut.replace_extension('').basename,
                width=BUTTON_WIDTH,
            )
            button.shortcut = shortcut
            print(f'Creating button for {shortcut.basename}')
            # Plus 1 because row 0 is the search box.
            button.grid(
                row=(index // column_count) + 1,
                column=index % column_count,
                padx=1,
                pady=1,
            )
            self.buttons.append(button)

    def _init_upper_controls(self):
        # The only way to add padding around the text entry is to put it in its
        # own frame element. Thanks Kevin
        # https://stackoverflow.com/a/51823093/5430534
        self.filter_var = tkinter.StringVar()
        self.filter_var.trace('w', self.filter)
        self.upper_frame = tkinter.Frame(self, bg=ENTRY_BG)
        self.filter_entry = tkinter.Entry(
            self.upper_frame,
            bg=ENTRY_BG,
            fg=MAIN_FG,
            insertbackground=MAIN_FG,
            relief=tkinter.FLAT,
            textvariable=self.filter_var,
        )
        self.filter_entry.bind('<Return>', self.launch_filtered)
        self.filter_entry.bind('<Escape>', self.quit)

        self.open_folder_button = tkinter.Button(
            self.upper_frame,
            text=FOLDER_EMOJI,
            bg=BUTTON_BG_NORMAL,
            fg=MAIN_FG,
            command=lambda: self.open_pgui_folder(),
        )

        self.upper_frame.columnconfigure(0, weight=1)
        self.upper_frame.grid(row=0, column=0, columnspan=999, sticky='ew', padx=8, pady=8)
        self.filter_entry.grid(row=0, column=0, sticky='news', padx=2, pady=2)
        self.open_folder_button.grid(row=0, column=1, sticky='news', padx=2, pady=2)
        return self.filter_entry

    def filter(self, *args):
        text = self.filter_entry.get().lower()
        enabled = []
        for button in self.buttons:
            button.configure(bg=BUTTON_BG_NORMAL)
            if text == '' or text in button['text'].lower():
                button['state'] = 'normal'
                enabled.append(button)
            else:
                button['state'] = 'disabled'

        if len(enabled) == 1:
            enabled[0].configure(bg=BUTTON_BG_HIGHLIGHT)
            self.ready_to_launch = enabled[0]
        else:
            self.ready_to_launch = None

    def launch_filtered(self, *args):
        if self.ready_to_launch is None:
            return

        self.launch_program(self.ready_to_launch.shortcut)

    def launch_program(self, shortcut):
        print('opening application', shortcut.basename)
        os.chdir(shortcut.parent.absolute_path)
        command = f'"{shortcut.absolute_path}"'
        subprocess.Popen(command, shell=True)
        self.quit()

    def open_pgui_folder(self):
        if os.name == 'nt':
            command = ['explorer.exe', PGUI_FOLDER.absolute_path]
        else:
            command = ['xdg-open', PGUI_FOLDER.absolute_path]
        subprocess.Popen(command, shell=True)

    def quit(self, *args):
        return super().quit()

@vlogging.main_decorator
def main(argv):
    root = tkinter.Tk()
    root.withdraw()
    root.title('PGUI')
    root.resizable(0,0)

    pgui = PGUILauncher(root)
    pgui.pack(fill=tkinter.BOTH, expand=True)
    pgui.filter_entry.focus()

    width = root.winfo_reqwidth()
    height = root.winfo_reqheight()
    x_offset = (root.winfo_screenwidth() - width) / 2
    y_offset = (root.winfo_screenheight() - height) / 2

    root.geometry('%dx%d+%d+%d' % (width, height, x_offset, y_offset-50))
    root.deiconify()
    root.mainloop()

if __name__ == '__main__':
    raise SystemExit(main(sys.argv[1:]))
