#!/usr/bin python3
""" The command frame for Faceswap GUI """

import logging
import gettext
import tkinter as tk
from tkinter import ttk

from lib.utils import get_module_objects

from .control_helper import ControlPanel
from .custom_widgets import Tooltip
from .utils import get_images, get_config
from .options import CliOption

logger = logging.getLogger(__name__)

# LOCALES
_LANG = gettext.translation("gui.tooltips", localedir="locales", fallback=True)
_ = _LANG.gettext


class CommandNotebook(ttk.Notebook):  # pylint:disable=too-many-ancestors
    """ Frame to hold each individual tab of the command notebook """

    def __init__(self, parent):
        logger.debug("Initializing %s: (parent: %s)", self.__class__.__name__, parent)
        self.actionbtns = {}
        super().__init__(parent)
        parent.add(self)

        self.tools_notebook = ToolsNotebook(self)
        self.set_running_task_trace()
        self.build_tabs()
        self.modified_vars = self._set_modified_vars()
        get_config().set_command_notebook(self)
        logger.debug("Initialized %s", self.__class__.__name__)

    @property
    def tab_names(self):
        """ dict: Command tab titles with their IDs """
        return {self.tab(tab_id, "text").lower(): tab_id
                for tab_id in range(0, self.index("end"))}

    @property
    def tools_tab_names(self):
        """ dict: Tools tab titles with their IDs """
        return {self.tools_notebook.tab(tab_id, "text").lower(): tab_id
                for tab_id in range(0, self.tools_notebook.index("end"))}

    def set_running_task_trace(self):
        """ Set trigger action for the running task
            to change the action buttons text and command """
        logger.debug("Set running trace")
        tk_vars = get_config().tk_vars
        tk_vars.running_task.trace("w", self.change_action_button)

    def build_tabs(self):
        """ Build the tabs for the relevant command """
        logger.debug("Build Tabs")
        cli_opts = get_config().cli_opts
        for category in cli_opts.categories:
            book = self.tools_notebook if category == "tools" else self
            cmdlist = cli_opts.commands[category]
            for command in cmdlist:
                title = command.title()
                commandtab = CommandTab(book, category, command)
                book.add(commandtab, text=title)
        self.add(self.tools_notebook, text="Tools")
        logger.debug("Built Tabs")

    def change_action_button(self, *args):
        """ Change the action button to relevant control """
        logger.debug("Update Action Buttons: (args: %s", args)
        tk_vars = get_config().tk_vars

        for cmd, action in self.actionbtns.items():
            btnact = action
            if tk_vars.running_task.get():
                ttl = " Stop"
                img = get_images().icons["stop"]
                hlp = "Exit the running process"
            else:
                ttl = f" {cmd.title()}"
                img = get_images().icons["start"]
                hlp = f"Run the {cmd.title()} script"
            logger.debug("Updated Action Button: '%s'", ttl)
            btnact.config(text=ttl, image=img)
            Tooltip(btnact, text=hlp, wrap_length=200)

    def _set_modified_vars(self):
        """ Set the tkinter variable for each tab to indicate whether contents
        have been modified """
        tkvars = {}
        for tab in self.tab_names:
            if tab == "tools":
                for ttab in self.tools_tab_names:
                    var = tk.BooleanVar()
                    var.set(False)
                    tkvars[ttab] = var
                continue
            var = tk.BooleanVar()
            var.set(False)
            tkvars[tab] = var
        logger.debug("Set modified vars: %s", tkvars)
        return tkvars


class ToolsNotebook(ttk.Notebook):  # pylint:disable=too-many-ancestors
    """ Tools sit in their own tab, but need to inherit objects from the main command notebook """
    def __init__(self, parent):
        super().__init__(parent)
        self.actionbtns = parent.actionbtns


class CommandTab(ttk.Frame):  # pylint:disable=too-many-ancestors
    """ Frame to hold each individual tab of the command notebook """

    def __init__(self, parent, category, command):
        logger.debug("Initializing %s: (category: '%s', command: '%s')",
                     self.__class__.__name__, category, command)
        super().__init__(parent, name=f"tab_{command.lower()}")

        self.category = category
        self.actionbtns = parent.actionbtns
        self.command = command

        self.build_tab()
        logger.debug("Initialized %s", self.__class__.__name__)

    def build_tab(self):
        """ Build the tab """
        logger.debug("Build Tab: '%s'", self.command)
        options = get_config().cli_opts.opts[self.command]
        cp_opts = [val.cpanel_option for val in options.values() if isinstance(val, CliOption)]
        ControlPanel(self,
                     cp_opts,
                     label_width=16,
                     option_columns=3,
                     columns=1,
                     header_text=options.get("helptext", None),
                     style="CPanel")
        self.add_frame_separator()
        ActionFrame(self)
        logger.debug("Built Tab: '%s'", self.command)

    def add_frame_separator(self):
        """ Add a separator between top and bottom frames """
        logger.debug("Add frame seperator")
        sep = ttk.Frame(self, height=2, relief=tk.RIDGE)
        sep.pack(fill=tk.X, pady=(5, 0), side=tk.TOP)
        logger.debug("Added frame seperator")


class ActionFrame(ttk.Frame):  # pylint:disable=too-many-ancestors
    """Action Frame - Displays action controls for the command tab """

    def __init__(self, parent):
        logger.debug("Initializing %s: (command: '%s')", self.__class__.__name__, parent.command)
        super().__init__(parent)
        self.pack(fill=tk.BOTH, padx=5, pady=5, side=tk.BOTTOM, anchor=tk.N)

        self.command = parent.command
        self.title = self.command.title()

        self.add_action_button(parent.category,
                               parent.actionbtns)
        logger.debug("Initialized %s", self.__class__.__name__)

    def add_action_button(self, category, actionbtns):
        """ Add the action buttons for page """
        logger.debug("Add action buttons: '%s'", self.title)
        actframe = ttk.Frame(self)
        actframe.pack(fill=tk.X, side=tk.RIGHT)

        tk_vars = get_config().tk_vars
        var_value = f"{category},{self.command}"

        btngen = ttk.Button(actframe,
                            image=get_images().icons["generate"],
                            text=" Generate",
                            compound=tk.LEFT,
                            width=14,
                            command=lambda: tk_vars.generate_command.set(var_value))
        btngen.pack(side=tk.LEFT, padx=5)
        Tooltip(btngen,
                text=_("Output command line options to the console"),
                wrap_length=200)

        btnact = ttk.Button(actframe,
                            image=get_images().icons["start"],
                            text=f" {self.title}",
                            compound=tk.LEFT,
                            width=14,
                            command=lambda: tk_vars.action_command.set(var_value))
        btnact.pack(side=tk.LEFT, fill=tk.X, expand=True)
        Tooltip(btnact,
                text=_("Run the {} script").format(self.title),
                wrap_length=200)
        actionbtns[self.command] = btnact

        logger.debug("Added action buttons: '%s'", self.title)


__all__ = get_module_objects(__name__)
