#!/usr/bin/python

##
# Wacom tablets DBUS configurator v0.2
# Author: Alexia Death
#
# Released under GPL v2 or later
# 
##

import dbus
import re
import os
import sys


# Option defs
path="/dev/input/"

#<- Helper functions ->

#Parse prefs file
def parsePrefs(s):
    """Parse a string into a dictionary."""
    #Fetch a *copy* of the default dictionary.
    ret = {}
    #Split lines.
    lines = s.split("\n")
    #Loop through lines.
    for line in lines:
        #Strip whitespace.
        line = line.strip()
        #Skip comment and blank lines.
        if line and line[0] != "#":
            #Split the line in the pair key, value
            values = line.split('=')
            #Fill dictionary.
            ret[values[0]] = values[1]
    #Return dictionary.
    return ret

#load prefs
def loadPrefs( prefsFile, devid ):
    f = file(prefsFile)
    try:
         #Read whole file as one string.
         data = f.read()
    finally:
         #Close file
         f.close()
    #Parse data string.
    conf = parsePrefs(data)
    print 'FIXME: Injection hole. Fix before any deployment or risk somebody putting "DebugLevel 11; rm -rf /;" in conf and nuking the os.'
    for key, value in conf.items():
        os.system('xsetwacom set '+devid+' '+key+' '+str(value)) #NOTE: Doing this is rather a bad idea. Anything can and will be executed.
    return

#function to load device preferences stored for user under ~/.wacom/<devid>
def loadDevicePrefs( devid ):
    print 'Loading any prefs for',devid,'if available...'
    try:
         userPrefs = os.environ["HOME"]+'/.wacom/'+devid
    except KeyError, e:
         print 'Cant set user prefs, no home defined.'
         userPrefs = 0

    sysPrefs  = '/etc/wacom/'+devid
    if   not userPrefs == 0 and os.path.exists(userPrefs) and os.path.isfile(userPrefs):
        loadPrefs( userPrefs, devid )
        print 'User prefs <hopefully> loaded...'
    else:
        if os.path.exists(sysPrefs) and os.path.isfile(sysPrefs):
            loadPrefs( sysPrefs, devid )
            print 'System prefs <hopefully> loaded...'
        else:
            print 'No prefs found!'
    return

#Function to add devices with intelligent names.
def addDevice( devname, devtype, xinput_iface ):
    print 'Adding', devtype, 'for this device...'
    devid = devtype+'-wacom-'+devname
    result = xinput_iface.add( ['driver', 'wacom'], ['identifier', devid], ['Type', devtype], ['Device', path+devname])
    if result > 0:
        print 'Device added with id:', result
        loadDevicePrefs( devid )
    else:
        print 'Device add failed with error:', result
    return result

#<- Main functions ->
def load():
    bus = dbus.SystemBus()
    xinput = bus.get_object('org.x.config.display0',
                            '/org/x/config/0')
    xinput_iface = dbus.Interface(xinput,
                   dbus_interface='org.x.config.input')

    devices = xinput_iface.listDevices()

    #re for finding any wacom instances existing
    findXWacom = re.compile('.*wacom.*', re.IGNORECASE)

    #count found devices
    devcount = 0
    devremcount = 0

    for Value in devices:
        m = findXWacom.match( Value[1] )
        if m:
            print 'Found: ', m.group(), '. Removing.'
            devcount = devcount + 1
            result = xinput_iface.remove( Value[0] )
            if result == 0:
                print 'Removing ', Value[1], ' done...'
                devremcount = devremcount + 1
            else:
                print 'Removing ', Value[1], ' failed: error ', result
    if devcount == 0:
         print 'No active devices found to remove.'
    else:
         print 'Devices found/removed:', devcount, '/', devremcount
    
    findDevWacom     = re.compile('.*tablet-.*', re.IGNORECASE)
    findDevHasPad    = re.compile('(.*bamboo.*)|(.*intuos.*)', re.IGNORECASE)
    findDevHasCursor = re.compile('(.*graphire.*)|(.*intuos.*)', re.IGNORECASE)
    findDevHasTouch  = re.compile('(.*cintiq.*)', re.IGNORECASE)
    
    dirList=os.listdir(path)
    
    
    for fname in dirList:
        m = findDevWacom.match( fname )
        if m:
             print 'Found tablet device: path =',path+fname, 'name =',fname

    # All wacoms have stylus and eraser.
    
             addDevice(fname, 'stylus', xinput_iface)
             #addDevice(fname, 'eraser', xinput_iface)

    # And some optional devices.         
             print 'Checking if device wants cursor...'
             m = findDevHasCursor.match( fname )
             if m:
              #    addDevice(fname, 'cursor', xinput_iface)
                  print '...'
             else:
                  print 'No. Moving on.'
    
             print 'Checking if device wants pad...'
             m = findDevHasPad.match( fname )
             if m:
               #   addDevice(fname, 'pad', xinput_iface)
                  print '...'
             else:
                  print 'No. Moving on.'

             print 'Checking if device wants touch...'
             m = findDevHasTouch.match( fname )
             if m:
                #  addDevice(fname, 'touch', xinput_iface)
                  print '...'
             else:
                  print 'No. Moving on.'
    return

def remove():
    bus = dbus.SystemBus()
    xinput = bus.get_object('org.x.config.display0',
                            '/org/x/config/0')
    xinput_iface = dbus.Interface(xinput,
                   dbus_interface='org.x.config.input')

    devices = xinput_iface.listDevices()

    #re for finding any wacom instances existing
    findXWacom = re.compile('.*wacom.*', re.IGNORECASE)

    #count found devices
    devcount = 0
    devremcount = 0

    for Value in devices:
        m = findXWacom.match( Value[1] )
        if m:
            print 'Found: ', m.group(), '. Removing.'
            devcount = devcount + 1
            result = xinput_iface.remove( Value[0] )
            if result == 0:
                print 'Removing ', Value[1], ' done...'
                devremcount = devremcount + 1
            else:
                print 'Removing ', Value[1], ' failed: error ', result
    if devcount == 0:
         print 'No active devices found to remove.'
    else:
         print 'Devices found/removed:', devcount, '/', devremcount
    return

def reconfigureAll():
    bus = dbus.SystemBus()
    xinput = bus.get_object('org.x.config.display0',
                            '/org/x/config/0')
    xinput_iface = dbus.Interface(xinput,
                   dbus_interface='org.x.config.input')

    devices = xinput_iface.listDevices()

    #re for finding any wacom instances existing
    findXWacom = re.compile('.*wacom.*', re.IGNORECASE)

    #count found devices
    devcount = 0

    for Value in devices:
        m = findXWacom.match( Value[1] )
        if m:
            print 'Found: ', m.group(), '. Reconfiguring.'
            devcount = devcount + 1
            loadDevicePrefs( Value[1] )
    if devcount == 0:
         print 'No active devices found to reconfigure.'
    else:
         print 'Devices reconfigured:', devcount

    return

def usage():
     print 'Usage: tabletbus.py [load|remove|reconfigure [all|<device id>]]'

# Main switching function
if len(sys.argv) > 1:
    if sys.argv[1] == 'load':
         load()

    elif sys.argv[1] == 'remove':
         remove()

    elif sys.argv[1] == 'reconfigure':
         if len(sys.argv) > 2:
              if sys.argv[2] == 'all':
                   reconfigureAll();
              else:
                   loadDevicePrefs( sys.argv[2] )
         else:
              usage()
    else:
         usage()

else:
    usage()

