#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# This script reads the keybinds configuration file ("$HOME/.config/openbox/rc.xml")
# and writes them to a text file ("$HOME/.config/openbox/kbinds.txt").
# The script is used by mb-kb-pipemenu to pipe the output to the Openbox menu,
# or to display keybinds in a separate window.
#
# Based on a script by wlourf 07/03/2010
# http://u-scripts.blogspot.com/2010/03/how-to-display-openboxs-shortcuts.html
#
# Written by damo <damo@bunsenlabs.org> for BunsenLabs Linux, April 2015
# Ported to Manjaro by napcok <napcok@gmail.com> March 2016
# Fix (multi-action keybinds): prefer Execute over first action — musqz

import sys
import os
import datetime

try:
    from lxml import etree
except ImportError:
    import xml.etree.ElementTree as etree

rc_fpath = os.environ["HOME"] + "/.config/openbox/rc.xml"
kb_fpath = os.environ["HOME"] + "/.config/openbox/kbinds.txt"
arrShortcut = []
gui = False


def cmdargs():
    if len(sys.argv) > 1:
        if sys.argv[1] == "--gui":
            return True
        else:
            msg  = "\n\n\tUSAGE: to display keybinds in a text window use 'mb-kb --gui &>/dev/null'\n\n"
            msg += "\tRunning the script without args will send output to the terminal\n\n"
            print(msg)
            sys.exit()
    return False


def keyboard():
    strRoot = "{http://openbox.org/3.4/rc}"
    tree = etree.parse(rc_fpath)
    root = tree.getroot()

    for k in root.findall(strRoot + "keyboard/" + strRoot + "keybind"):
        key = k.get("key")

        # Collect ALL actions for this keybind (fixes multi-action entries like
        # Unmaximize + Execute where the old k.find() only saw the first one).
        actions = k.findall(strRoot + "action")
        if not actions:
            continue

        # Priority: Execute > MoveResizeTo > first action
        # This ensures tiling keybinds (Unmaximize + MoveResizeTo) show geometry
        # instead of the preceding window-state action.
        action_element = next(
            (a for a in actions if a.get("name") == "Execute"),
            next(
                (a for a in actions if a.get("name") == "MoveResizeTo"),
                actions[0]
            )
        )

        strTxt  = ""
        strType = "o "
        arrShortcut.append((key, "", ""))

        if action_element.get("name") == "Execute":
            name_element    = action_element.find(strRoot + "name")
            command_element = action_element.find(strRoot + "command")
            exec_element    = action_element.find(strRoot + "execute")
            strType = "x "
            if name_element is not None:
                strTxt = name_element.text
            elif command_element is not None:
                strTxt = command_element.text
            elif exec_element is not None:
                strTxt = exec_element.text
        elif action_element.get("name") == "MoveResizeTo":
            parts = []
            for tag in ("x", "y", "width", "height"):
                el = action_element.find(strRoot + tag)
                if el is None:
                    el = action_element.find(tag)   # fallback: no namespace
                if el is not None and el.text:
                    parts.append(tag + ":" + el.text.strip())
            strTxt = "MoveResizeTo " + " ".join(parts) if parts else "MoveResizeTo"
        elif action_element.get("name") == "ShowMenu":
            menu_element = action_element.find(strRoot + "menu")
            if menu_element is not None:
                strTxt = menu_element.text
        else:
            action_name = action_element.get("name")
            if action_name is not None:
                strTxt = action_name

        arrShortcut[len(arrShortcut) - 1] = (strType, key, strTxt)


def output_keybinds(arrShortcut, gui):
    for i in range(len(arrShortcut)):
        exe        = str(arrShortcut[i][0])
        keybinding = str(arrShortcut[i][1])
        execute    = str(arrShortcut[i][2])
        if gui:
            if len(execute) > 80:
                execute = execute[:75] + "....."
            line = "{:2}".format(i) + "\t" + "{:<16}".format(keybinding) \
                   + "\t" + execute
        else:
            line = exe + "{:<16}".format(keybinding) + "\t" + execute
        print(line)
        write_file(line)


def check_rcfile(fpath, mode):
    try:
        open(fpath, mode).close()
    except IOError:
        return False
    return True


def write_file(line):
    with open(kb_fpath, 'a') as f:
        f.write(line + "\n")


def check_txtfile(kb_fpath):
    try:
        open(kb_fpath, 'w').close()
    except IOError:
        return False
    return True


if __name__ == "__main__":
    gui = cmdargs()
    check_txtfile(kb_fpath)

    if gui:
        write_file(str(datetime.date.today()) + "\trc.xml KEYBINDS")
        write_file("-------------------------------\n")

    if check_rcfile(rc_fpath, "r"):
        keyboard()
        output_keybinds(arrShortcut, gui)
    else:
        print("\nCan't open rc.xml for parsing\n\tCheck the filepath: " + rc_fpath + "\n")
        sys.exit(1)

    if gui:
        dlg  = "yad --text-info --title='Mabox Openbox Keybinds' "
        dlg += "--window-icon=distributor-logo-mabox --image=/usr/share/icons/mabox_trans_64.png "
        dlg += "--text '\n<b>Key bindings</b> are configured in your <i>~/.config/openbox/rc.xml</i> file.  <a href=\"http://openbox.org/help/Bindings\">docs</a>\n\t\t\t\t<b>S</b> - Shift key\n\t\t\t\t<b>C</b> - Control key\n\t\t\t\t<b>A</b> - Alt key\n\t\t\t\t<b>W</b> - Super key (usually bound to the Windows key)' "
        dlg += "--filename=$HOME/.config/openbox/kbinds.txt "
        dlg += "--width=640 --height=560 --fontname=Monospace "
        dlg += "--button='Edit rc.xml:geany -l 179 " + rc_fpath + "' --button='Reload Openbox configuration:openbox --reconfigure' --button=Close"
        os.system(dlg)
