#!/usr/bin/env python3

'''
ABOUT
  This is a simple script to clean up the Openbox menu. It will remove items
  containing obsolete commands. It will print the filtered menu to STDOUT and a
  list of removed commands to STDERR.

USAGE

    obmenucleaner [<filepath>]

  The filepath is optional. If no filepath is given, the XDG configuration
  directories will be scanned for the Openbox menu.xml file.

  To save the filtered menu, redirect it to a new file, e.g.

    obmenucleaner >new.xml

  Do not redirect it to the original as you will overwrite the menu before it is
  read. Check the output and if you are satisfied, copy it over the original.

SUGGESTIONS
  ObFileBrowser provides a pipe menu of all desktop files found on the system,
  organized by both name and category. It thus provides an automatic application
  menu that requires no maintenance. Additional desktop files can be created
  with Mimeo.

AUTHOR
  Xyne, 2011

'''

import os
from sys import exit, stderr, argv
from xml.dom.minidom import parse
from shlex import split


################################################################################
# From Mimeo
################################################################################

# The following is taken directly from the Mimeo module.


# Split a list of semi-colon-separated items.
def split_list(items, sep=';'):
  return map(str.strip, items.strip(sep).split(sep))

# Get environment paths
def get_paths(var):
  paths = os.getenv(var)
  if paths:
    return split_list(paths, sep=os.pathsep)
  else:
    return []

# Emulate the system command "which".
def which(cmd):
  if not cmd:
    return None
  def isExecutable(fpath):
    return os.path.exists(fpath) and os.access(fpath, os.X_OK)
  fpath, fname = os.path.split(cmd)
  if fpath:
    cmd = os.path.abspath(cmd)
    if isExecutable(cmd):
      return cmd
  else:
    for p in get_paths("PATH"):
      fpath = os.path.join(p, fname)
      if isExecutable(fpath):
        return fpath
  return None

################################################################################




def main():
  # If the user has specified a menu file, use it.
  try:
    menuPath = argv[1]

  # Otherwise check the XDG configuration paths.
  except IndexError:
    configDirs = list( get_paths('XDG_CONFIG_HOME') )
    configDirs.extend( get_paths('XDG_CONFIG_DIRS') )

    for d in configDirs:
      c = os.path.join(d, 'openbox', 'menu.xml')
      if os.path.isfile(c):
        menuPath = c
        break
    else:
      stderr.write('error: no menu.xml file found\n')
      exit(1)

  try:
    menuDom = parse(menuPath)
    commands = menuDom.getElementsByTagName('command')
    for command in commands:
      cmd = command.childNodes[0].data
      exe = which(split(cmd)[0])
      if not exe:
        stderr.write("removing %s\n" % (cmd))
        item = command.parentNode.parentNode
        menu = item.parentNode
        menu.removeChild(item)

    print(menuDom.toxml())

  except IOError as e:
    stderr.write('error: %s (%s)\n' % (e.strerror, e.filename))
    exit(1)

if __name__ == '__main__':
  main()
