"""
This is file used to listen to windows context menu registry action
"""
import os
import sys
from collections import namedtuple
from collections import OrderedDict

# Global variables
CMD_MAP = namedtuple("COMMAND_MAP", ["name", "method", "prompt_name"])


class RegistryListener(object):
  """
  XmlCli Class which provides methods to execute for registry
  """
  def __init__(self, xmlcli_path=None):
    from xmlcli import XmlCli as cli
    from xmlcli.common import utils
    self.xmlcli_path = xmlcli_path if xmlcli_path else os.path.dirname(cli.__file__)

    self.cli = cli
    print(f"script used from: {cli}")
    print(f"script path: {self.xmlcli_path}")

    self.interface = "stub" if len(sys.argv) <= 2 else sys.argv[2]
    self.command = "all" if len(sys.argv) <= 3 else sys.argv[3]
    bin_arg_path = "" if len(sys.argv) <= 1 else f"{sys.argv[1]}"
    # validate safe path
    if bin_arg_path and utils.is_safe_path(os.getcwd(), bin_arg_path):
      self.binary_file_path = os.path.abspath(bin_arg_path)
      self.binary_file_name = os.path.basename(self.binary_file_path)
      self.output_directory = os.path.dirname(self.binary_file_path)
      print(self.output_directory)
    else:
      pass
      # raise utils.XmlCliException("Unsafe file path used...")
    self.command_method_map = OrderedDict({
      "all"         : CMD_MAP("all", self.command_all, "Run All"),
      "savexml"     : CMD_MAP("savexml", self.command_savexml, "Save XML"),
      "generatejson": CMD_MAP("generatejson", self.command_generate_json, "Parse firmware as json"),
      "shell"       : CMD_MAP("shell", self.command_launch_shell, "Launch Shell"),
    })

  def create_registry_file(self, context_menu_name="XmlCli Menu", icon=""):
    from xmlcli import __version__

    command_content = f"""
; --------------------------------------------------------------------------------------------------
[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CommandStore\\shell\\version]
@="Version - {__version__}"
"Icon"="{icon},0"
"""
    sub_commands = "version;"
    registry_file_path = __file__.replace("\\", "\\\\")
    python_path = sys.executable.replace("\\", "\\\\")
    for key, cmd in self.command_method_map.items():
      sub_commands += f"{cmd.name};"
      command_content += f"""
; --------------------------------------------------------------------------------------------------
[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CommandStore\\shell\\{cmd.name}]
@="{cmd.prompt_name}"
"Icon"="{icon},0"

[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CommandStore\\shell\\{cmd.name}\\command]
@="\\"{python_path}\\" \\"{registry_file_path}\\" \\"%1\\" stub {cmd.name}"
"""

    menu_content = f"""Windows Registry Editor Version 5.00

; Registry file generated by XmlCli to register/update context menu
[HKEY_CLASSES_ROOT\\*\\shell\\{context_menu_name.replace(" ", "")}]
"MUIVerb"="{context_menu_name}"
"SubCommands"="{sub_commands}"
"Icon"="{icon},0"
"""
    registry_content = menu_content + command_content
    return registry_content

  def command_all(self):
    """
    Execute all commands except for launching
    :return:
    """
    self.output_directory = os.path.join(self.output_directory, os.path.splitext(self.binary_file_name)[0])
    os.makedirs(self.output_directory, exist_ok=True)
    print(self.output_directory)
    for key, cmd in self.command_method_map.items():
      if cmd.name not in ("gengui", "all"):
        cmd.method()

  def command_generate_json(self):
    from xmlcli.common import bios_fw_parser as parser

    print("script used from: ", parser)
    uefi_parser = parser.UefiParser(bin_file=self.binary_file_path, clean=False)
    output = uefi_parser.parse_binary()
    output = uefi_parser.sort_output_fv(output)
    output_json_file = os.path.join(self.output_directory, "{}.json".format(self.binary_file_name))
    uefi_parser.write_result_to_file(output_json_file, output_dict=output)

  def command_savexml(self):
    output_xml_file = os.path.join(self.output_directory, "{}.xml".format(self.binary_file_name))

    if self.interface == "stub":
      self.cli.savexml(output_xml_file, self.binary_file_path)
    else:
      self.cli.clb._setCliAccess(self.interface)
      self.cli.savexml(output_xml_file)

  def command_launch_shell(self):
    import subprocess

    startup_script = os.path.join(self.xmlcli_path, "start_xmlcli.py")
    cmd = [sys.executable, "-i", startup_script]
    subprocess.check_call(cmd)


if __name__ == "__main__":
  try:
    XMLCLI_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
    registry_listener = RegistryListener(xmlcli_path=XMLCLI_DIR)

    cmd_method = registry_listener.command_method_map.get(registry_listener.command, "shell")
    cmd_method.method()

  except Exception as e:
    print(e)

  input("Press any key to exit")
