# help.py - help utilities for PythonWin.
import os

import regutil
import win32api
import win32con
import win32ui

htmlhelp_handle = None

html_help_command_translators = {
    win32con.HELP_CONTENTS: 1,  # HH_DISPLAY_TOC
    win32con.HELP_CONTEXT: 15,  # HH_HELP_CONTEXT
    win32con.HELP_FINDER: 1,  # HH_DISPLAY_TOC
}


def FinalizeHelp():
    global htmlhelp_handle
    if htmlhelp_handle is not None:
        import win32help

        try:
            # frame = win32ui.GetMainFrame().GetSafeHwnd()
            frame = 0
            win32help.HtmlHelp(frame, None, win32help.HH_UNINITIALIZE, htmlhelp_handle)
        except win32help.error:
            print("Failed to finalize htmlhelp!")
        htmlhelp_handle = None


def OpenHelpFile(fileName, helpCmd=None, helpArg=None):
    "Open a help file, given a full path"
    # default help arg.
    win32ui.DoWaitCursor(1)
    try:
        if helpCmd is None:
            helpCmd = win32con.HELP_CONTENTS
        ext = os.path.splitext(fileName)[1].lower()
        if ext == ".hlp":
            win32api.WinHelp(
                win32ui.GetMainFrame().GetSafeHwnd(), fileName, helpCmd, helpArg
            )
        # XXX - using the htmlhelp API wreaks havoc with keyboard shortcuts
        # so we disable it, forcing ShellExecute, which works fine (but
        # doesn't close the help file when Pythonwin is closed.
        # Tom Heller also points out
        # https://web.archive.org/web/20070519165457/http://www.microsoft.com:80/mind/0499/faq/faq0499.asp ,
        # which may or may not be related.
        elif 0 and ext == ".chm":
            import win32help

            global htmlhelp_handle
            helpCmd = html_help_command_translators.get(helpCmd, helpCmd)
            # frame = win32ui.GetMainFrame().GetSafeHwnd()
            frame = 0  # Don't want it overlapping ours!
            if htmlhelp_handle is None:
                htmlhelp_hwnd, htmlhelp_handle = win32help.HtmlHelp(
                    frame, None, win32help.HH_INITIALIZE
                )
            win32help.HtmlHelp(frame, fileName, helpCmd, helpArg)
        else:
            # Hope that the extension is registered, and we know what to do!
            win32api.ShellExecute(0, "open", fileName, None, "", win32con.SW_SHOW)
        return fileName
    finally:
        win32ui.DoWaitCursor(-1)


def ListAllHelpFiles():
    ret = []
    ret = _ListAllHelpFilesInRoot(win32con.HKEY_LOCAL_MACHINE)
    # Ensure we don't get dups.
    for item in _ListAllHelpFilesInRoot(win32con.HKEY_CURRENT_USER):
        if item not in ret:
            ret.append(item)
    return ret


def _ListAllHelpFilesInRoot(root):
    """Returns a list of (helpDesc, helpFname) for all registered help files"""

    retList = []
    try:
        key = win32api.RegOpenKey(
            root, regutil.BuildDefaultPythonKey() + "\\Help", 0, win32con.KEY_READ
        )
    except win32api.error as exc:
        import winerror

        if exc.winerror != winerror.ERROR_FILE_NOT_FOUND:
            raise
        return retList
    try:
        keyNo = 0
        while 1:
            try:
                helpDesc = win32api.RegEnumKey(key, keyNo)
                helpFile = win32api.RegQueryValue(key, helpDesc)
                retList.append((helpDesc, helpFile))
                keyNo += 1
            except win32api.error as exc:
                import winerror

                if exc.winerror != winerror.ERROR_NO_MORE_ITEMS:
                    raise
                break
    finally:
        win32api.RegCloseKey(key)
    return retList


def SelectAndRunHelpFile():
    from pywin.dialogs import list

    helpFiles = ListAllHelpFiles()
    if len(helpFiles) == 1:
        # only 1 help file registered - probably ours - no point asking
        index = 0
    else:
        index = list.SelectFromLists("Select Help file", helpFiles, ["Title"])
    if index is not None:
        OpenHelpFile(helpFiles[index][1])


helpIDMap = None


def SetHelpMenuOtherHelp(mainMenu):
    """Modifies the main Help Menu to handle all registered help files.
    mainMenu -- The main menu to modify - usually from docTemplate.GetSharedMenu()
    """

    # Load all help files from the registry.
    global helpIDMap
    if helpIDMap is None:
        helpIDMap = {}
        cmdID = win32ui.ID_HELP_OTHER
        excludeList = ["Main Python Documentation", "Pythonwin Reference"]
        firstList = ListAllHelpFiles()
        # We actually want to not only exclude these entries, but
        # their help file names (as many entries may share the same name)
        excludeFnames = []
        for desc, fname in firstList:
            if desc in excludeList:
                excludeFnames.append(fname)

        helpDescs = []
        for desc, fname in firstList:
            if fname not in excludeFnames:
                helpIDMap[cmdID] = (desc, fname)
                win32ui.GetMainFrame().HookCommand(HandleHelpOtherCommand, cmdID)
                cmdID += 1

    helpMenu = mainMenu.GetSubMenu(
        mainMenu.GetMenuItemCount() - 1
    )  # Help menu always last.
    otherHelpMenuPos = 2  # can't search for ID, as sub-menu has no ID.
    otherMenu = helpMenu.GetSubMenu(otherHelpMenuPos)
    while otherMenu.GetMenuItemCount():
        otherMenu.DeleteMenu(0, win32con.MF_BYPOSITION)

    if helpIDMap:
        for id, (desc, fname) in helpIDMap.items():
            otherMenu.AppendMenu(win32con.MF_ENABLED | win32con.MF_STRING, id, desc)
    else:
        helpMenu.EnableMenuItem(
            otherHelpMenuPos, win32con.MF_BYPOSITION | win32con.MF_GRAYED
        )


def HandleHelpOtherCommand(cmd, code):
    OpenHelpFile(helpIDMap[cmd][1])
